contest 0816 crow [DP][倍增]
我做了一个半小时才发现把题读错了QAQ
感谢好心的出题人下来描述了一遍题意
反正在树上往上跳的操作就用倍增
我当初知道自己读错题之后意识模糊,啥也不知道了(最后比赛结束前半个小时以为比赛结束了,把代码放进压缩包准备上交时才发现大家根本没有躁动,然后才知道比赛还有半个小时……)
还有,如果调试代码调试地意识模糊,最好重写一遍,这样多半就能减少很多错误。
40pts
这道题的暴力超级好打
不过好像出题人无意中卡了常,有可能标算和暴力的分数是一样的
DP方程:
其中 在 上方,且 与 的距离小于等于
然后暴力找出 并取
100pts
就把暴力找 变成倍增
代码
#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;
}