倍增,延迟标记。
考虑一个$u$给他的哪几个祖先$v$贡献了$1$。越往上$dis(v,u)$越大,找到最远的一个还满足条件的$v$,$v$到$u$的父亲这条链上的答案都$+1$。延迟标记一下,然后从叶子节点往上走一遍求前缀和即可。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<ctime> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0); void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } template <class T> inline void read(T &x) { char c = getchar(); x = 0; while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + c - ‘0‘; c = getchar(); } } int n; long long a[200010]; int to[200010][35]; long long len[200010][35]; struct Edge { int v; long long w; }e[200010]; vector<int>G[200010]; int ans[200010]; int get(int x) { long long L=0; int res=x,y=x; while(1) { int flag=0; for(int j=30;j>=0;j--) { if(len[res][j]==-1) continue; if(len[res][j]+L>a[y]) continue; flag=1; L=len[res][j]+L; res=to[res][j]; break; } if(flag==0) break; } return res; } void dfs(int x,int fa,int idx,int dep) { to[x][0]=fa; if(idx!=-1) len[x][0]=e[idx].w; else len[x][0]=-1; for(int j=1;j<=30;j++) { if((1<<j)>dep) { to[x][j]=-1; len[x][j]=-1; continue; } to[x][j]=to[to[x][j-1]][j-1]; len[x][j]=len[x][j-1]+len[to[x][j-1]][j-1]; } int y=get(x); if(y!=x) { if(to[x][0]!=-1) ans[to[x][0]]++; if(to[y][0]!=-1) ans[to[y][0]]--; } for(int i=0;i<G[x].size();i++) { int id=G[x][i]; dfs(e[id].v,x,id,dep+1); } } void F(int x) { for(int i=0;i<G[x].size();i++) { int id=G[x][i]; F(e[id].v); ans[x]+=ans[e[id].v]; } } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n-1;i++) { int fa; cin>>fa; e[i].v=i+1; cin>>e[i].w; G[fa].push_back(i); } dfs(1,-1,-1,0); F(1); for(int i=1;i<=n;i++) cout<<ans[i]<<" "; cout<<endl; return 0; }
CodeForces 740D Alyona and a tree
原文:http://www.cnblogs.com/zufezzt/p/6397075.html