codeforces 208E Blood Cousins (dsu on tree + 倍增 )
阿新 • • 發佈:2018-12-09
題意: 現在有若干棵樹,對於每次一詢問,都有一個節點 u 和一個 k 你要求出在這棵樹上與u 同為k 級兄弟的節點個數,也就是與u的k級父親是同一個父親的,節點個數。
思路: 對於每一個節點u和k ,如果他的深度<k 那麼肯定是找不到的,答案為0 ,否則,我先找到的他的k級父親,也就是詢問這個節點有多少k級孩子。k級孩子的個數-1 ,那麼如何在nlogn 的時間內找到他的k級孩子的個數。當然就是dsu on tree 的問題了。
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int ,int > pii; const int N =100010; const int DEG=20; struct Edge { int v; int next; }edge[N*2]; int head[N],tot; int fa[N][21]; int deg[N]; void init() { memset(head,-1,sizeof(head)); tot=0; } void adde(int u,int v) { edge[++tot].v=v; edge[tot].next=head[u]; head[u]=tot; } void bfs(int root) { queue< int >que; deg[root]=0; que.push(root); while(!que.empty()){ int tmp=que.front(); que.pop(); for(int i=1;i<DEG;i++) fa[tmp][i]=fa[fa[tmp][i-1]][i-1]; for(int i=head[tmp];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==fa[tmp][0] ) continue; deg[v]=deg[tmp]+1; fa[v][0]=tmp; que.push(v); } } } int find_kfa(int x,int k) { for(int i=0;i<DEG;i++){ if((k>>i)&1) x=fa[x][i]; } return x; } int n,m; int sz[N]; bool big[N]; int ans[N]; int rt[N]; int rttot; vector< pii >ve[N]; struct node { int u; int k; int ans; }xun[N]; void dfs(int u) { sz[u]=1; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; dfs(v); sz[u]+=sz[v]; } return ; } void add(int u,int flag) { if(flag==1){ ans[deg[u]]++; } else ans[deg[u]]--; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(big[v]) continue; add(v,flag); } } void dfs1(int u,int keep) { int mx=-1,bigc=-1; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(sz[v]>mx){ mx=sz[v]; bigc=v; } } for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==bigc) continue; dfs1(v,0); } if(bigc!=-1){ dfs1(bigc,1); big[bigc]=1; } add(u,1); /*cout<<"**** u "<<u<<endl; for(int i=0;i<=n;i++){ cout<<ans[i]<<" "; } cout<<endl; */ for(int i=0;i<ve[u].size();i++){ int k=ve[u][i].first; int id=ve[u][i].second; if(k+deg[u]<=n) xun[id].ans=max(ans[deg[u]+k]-1,0); } if(bigc!=-1){ big[bigc]=0; } if(keep==0) add(u,-1); } int main() { scanf("%d",&n); init(); int x; for(int i=1;i<=n;i++){ scanf("%d",&x); if(x==0){ rt[++rttot]=i; } else{ adde(x,i); } } for(int i=1;i<=rttot;i++){ bfs(rt[i]); } scanf("%d",&m); int u,k; for(int i=1;i<=m;i++){ scanf("%d %d",&xun[i].u,&xun[i].k); u=xun[i].u; k=xun[i].k; if(deg[u]<k){ xun[i].ans=0; continue; } int kfa=find_kfa(u,k); //cout<<" kfa "<<kfa<<endl; ve[kfa].push_back(pii(k,i)); } for(int i=1;i<=rttot;i++){ dfs(rt[i]); dfs1(rt[i],0); } for(int i=1;i<=m;i++){ printf("%d ",xun[i].ans); } return 0; } /* */