CF375D Tree and Queries(dsu)

link

思路:

开个桶表示每个颜色出现的次数,再用(d[i])数组表示出现次数(>=i)的颜色个数。
注意计算贡献时的细节。

if(c==-1)
        d[val[col[u]]]+=c;
    val[col[u]]+=c;
    if(c==1)
        d[val[col[u]]]+=c;

如果是消除贡献,先修改(d)数组,再修改桶;
如果是增加贡献,先修该桶,再修改(d)数组。

代码:

const int maxn=100000+100;

int n,m,col[maxn],ans[maxn];
vector<int>g[maxn];
struct node{
	int id,k;
};
vector<node>qask[maxn];
int son[maxn],siz[maxn],Son;

void dfs1(int u,int fa){
	siz[u]=1;
	for(int i=0;i<g[u].size();i++){
		int j=g[u][i];
		if(j==fa) continue;
		dfs1(j,u);
		siz[u]+=siz[j];
		if(siz[j]>siz[son[u]]||son[u]==0) son[u]=j;
	}	
}

int d[maxn],val[maxn],st[maxn];

void add(int u,int f,int c){
    if(c==-1)
        d[val[col[u]]]+=c;
    val[col[u]]+=c;
    if(c==1)
        d[val[col[u]]]+=c;
    for(int i=0;i<g[u].size();i++){
		int j=g[u][i];
		if(j==f||st[j]) continue;
		add(j,u,c);
	}
}

void dfs2(int u,int fa,int op){
	for(int i=0;i<g[u].size();i++){
		int j=g[u][i];
		if(j==fa||j==son[u]) continue;
		dfs2(j,u,1);
	}
	if(son[u]) dfs2(son[u],u,0),st[son[u]]=1;
	add(u,fa,1);
	for(int i=0;i<qask[u].size();i++){
		node t=qask[u][i];
		ans[t.id]=d[t.k];
	}
	if(son[u]) st[son[u]]=0;
	if(op) add(u,fa,-1);
}

int main(){
	n=read,m=read;
	rep(i,1,n) col[i]=read;
	rep(i,1,n-1){
		int u=read,v=read;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	rep(i,1,m){
		int u=read,k=read;
		qask[u].push_back({i,k});
	}
	dfs1(1,0);
	dfs2(1,0,1);
	rep(i,1,m) printf("%d
",ans[i]);
	
	return 0;
} 

原文地址:https://www.cnblogs.com/OvOq/p/15050363.html