【CF208E】Blood Cousins【dsu on tree】

传送门

Solution

可以将询问转化为询问点\(x\)\(K\)级儿子有多少个

也就是\(x\)子树内深度为\(dep[x]+k\)的点有多少个,

于是上dsu on tree就完了

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,cnt,first[N],ans[N];
struct node{
	int v,nxt;
}e[N<<1];
vector<pair<int,int> > que[N];
inline void add(int u,int v){
	e[++cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt;
}
int dep[N],hson[N],siz[N],pa[N][20];
inline void dfs(int u,int f){
	pa[u][0]=f;siz[u]=1;
	for(int i=1;i<=19;++i) pa[u][i]=pa[pa[u][i-1]][i-1];
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==f) continue;
		dep[v]=dep[u]+1;
		dfs(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[hson[u]]) hson[u]=v;
	}
}
inline int up(int u,int k){
	for(int i=19;i>=0;--i)
		if(k&(1<<i)) u=pa[u][i];
	return u;
}
int w[N],son;
inline void work(int u,int f,int tp){
	w[dep[u]]+=tp;
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==f||v==son) continue;
		work(v,u,tp);
	}
}
inline void dsu(int u,int f,int tp){
	for(int i=first[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==f||v==hson[u]) continue;
		dsu(v,u,0); 
	}
	if(hson[u]) dsu(hson[u],u,1),son=hson[u];
	work(u,f,1);son=0;
	for(int i=0;i<que[u].size();++i) ans[que[u][i].second]=w[que[u][i].first]-1;
	if(!tp) work(u,f,-1);
}
int main(){
	scanf("%d",&n);
	for(int i=1,f;i<=n;++i){
		scanf("%d",&f);
		if(!f) f=n+1;
		add(f,i);
	}
	scanf("%d",&m);
	dfs(n+1,0);
	for(int i=1,u,k;i<=m;++i){
		scanf("%d%d",&u,&k);
		int x=up(u,k);
		if(x==n+1||x==0) continue;
		que[x].push_back(make_pair(dep[u],i));
	}
	dsu(n+1,0,1);
	for(int i=1;i<=m;++i) printf("%d ",ans[i]);
	return 0;
}
posted @ 2021-01-09 20:06  cjTQX  阅读(39)  评论(0编辑  收藏  举报