P2720 小A的礼物 [dfs序 + 莫队]

传送门

题意 : 求每个子树中有多少种不同的颜色

我们先dfs处理出每棵子树的区间 , 然后莫队就好了

唯一需要注意的是 , dfs后需要将颜色按dfs序重新标号

#include<bits/stdc++.h>
#define N 100050
using namespace std;
int first[N],next[N],to[N],tot;
int st[N],ed[N],col[N],sign;
int n,m,pos[N],cnt[N],ans[N],tmp;
struct Node{int l,r,id;}q[N];
void add(int x,int y){
	next[++tot]=first[x],first[x]=tot,to[tot]=y;
}
bool cmp(Node a,Node b){
	if(pos[a.l]==pos[b.l]) return a.r<b.r;
	return pos[a.l]<pos[b.l];
}
void dfs(int u){
	st[u] = ++sign;
	for(int i=first[u];i;i=next[i]){
		int t=to[i]; dfs(t);
	} ed[u] = sign;
}
void add(int x){if(cnt[x]==0) tmp++; cnt[x]++;}
void del(int x){if(cnt[x]==1) tmp--; cnt[x]--;}
int main(){
	scanf("%d",&n); int siz = sqrt(n);
	for(int i=2;i<=n;i++){
		int x; scanf("%d",&x); add(x,i);
	} dfs(1); 
	for(int i=1;i<=n;i++){
		scanf("%d",&col[st[i]]); pos[i] = i/siz;
	} scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int x; scanf("%d",&x);
		q[i].l=st[x] , q[i].r=ed[x] , q[i].id=i;
	} sort(q+1,q+m+1,cmp); int l=1,r=0;
	for(int i=1;i<=m;i++){
		while(r<q[i].r) add(col[++r]); while(r>q[i].r) del(col[r--]);
		while(l<q[i].l) del(col[l++]); while(l>q[i].l) add(col[--l]);
		ans[q[i].id] = tmp;
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0;
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/85109170