contest 0816 crow [DP][倍增]

contest 0816 crow [DP][倍增]

我做了一个半小时才发现把题读错了QAQ

感谢好心的出题人下来描述了一遍题意

反正在树上往上跳的操作就用倍增

我当初知道自己读错题之后意识模糊,啥也不知道了(最后比赛结束前半个小时以为比赛结束了,把代码放进压缩包准备上交时才发现大家根本没有躁动,然后才知道比赛还有半个小时……)

还有,如果调试代码调试地意识模糊,最好重写一遍,这样多半就能减少很多错误

40pts

这道题的暴力超级好打

不过好像出题人无意中卡了常,有可能标算和暴力的分数是一样的

DP方程:

f [ x ] = m i n ( f [ y ] ) + v [ x ]

其中 y x 上方,且 x y 的距离小于等于 d [ x ]

然后暴力找出 y 并取 m i n

100pts

就把暴力找 y 变成倍增

代码

#include<stdio.h>
#include<iostream>
#define N 300005
#define ll long long
using namespace std;
ll End[N<<1],Next[N<<1],Last[N<<1],cnt;
ll Log[N],Dep[N],Fa[N][20],f[N][20];
ll Ans[N],v[N];ll d[N];
void Ins(ll x,ll y){
    End[++cnt]=y,Next[cnt]=Last[x],Last[x]=cnt;
}
ll jump(ll p,ll x){
    for(ll i=0;i<=Log[x];i++)
        if(x&(1ll<<i))p=Fa[p][i];
    return p;
}
void DFS(ll u,ll fa){
    if(u!=1){
        Dep[u]=Dep[fa]+1;
        Fa[u][0]=fa,f[u][0]=Ans[fa];
        for(ll i=1;i<=Log[Dep[u]];i++)
            Fa[u][i]=Fa[Fa[u][i-1]][i-1],
            f[u][i]=min(f[u][i-1],f[Fa[u][i-1]][i-1]);
        ll dis=min(d[u],Dep[u]);
        ll newu=jump(u,dis-(1ll<<Log[dis]));
        Ans[u]=min(f[u][Log[dis]],f[newu][Log[dis]])+v[u];
    }
    for(ll i=Last[u];i;i=Next[i])
        if(End[i]!=fa)DFS(End[i],u);
}
int main(){
    ll n;scanf("%lld",&n);
    Log[0]=-1;
    for(ll i=1;i<=n;i++)
        Log[i]=Log[i>>1ll]+1;
    for(ll i=1;i<n;i++){
        ll x,y;scanf("%lld%lld",&x,&y);
        Ins(x,y),Ins(y,x);
    }
    for(ll i=1;i<=n;i++)
        scanf("%lld%lld",&v[i],&d[i]);
    DFS(1,0);
    ll q;scanf("%d",&q);
    for(ll i=1;i<=q;i++){
        ll x;scanf("%d",&x);
        printf("%lld\n",Ans[x]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ArliaStark/article/details/81805137