P9233
题意
给定一棵树,求有多少棵子树:出现过的颜色出现次数均相等。
做法
yt 说:“要用树上启发式合并。”于是这题我们就用了树上启发式合并。
一看子树颜色就感觉很板,然后颜色出现次数均相等就需要记录
然后这题唯一有一点细节是:我们维护的是出现过的最小值,即不会等于 0。那么我们在对一种颜色进行
时间复杂度
代码
#include<bits/stdc++.h>
using namespace std;
int n,num_edge,ans,mi,ma;
struct Edge{
int to,next;
}e[400010];
int head[200010];
int a[200010];
int siz[200010];
int son[200010];
int t[2][200010];
void add_edge(int from,int to){
e[++num_edge].to=to;
e[num_edge].next=head[from];
head[from]=num_edge;
}
void add(int x){
t[1][t[0][x]]--;
t[0][x]++;
t[1][t[0][x]]++;
if(t[0][x]<mi) mi=t[0][x];
if(t[0][x]>ma) ma=t[0][x];
if(!t[1][mi]) mi++;
}
void del(int x){
t[1][t[0][x]]--;
t[0][x]--;
t[1][t[0][x]]++;
if(t[0][x]&&t[0][x]<mi) mi=t[0][x];
if(!t[1][ma]) ma--;
}
void dfs0(int u){
int v;
siz[u]=1;
for(int i=head[u];i;i=e[i].next){
v=e[i].to;
dfs0(v);
if(siz[v]>siz[son[u]]) son[u]=v;
siz[u]+=siz[v];
}
}
void dfs1(int u,int ty){
int v;
if(!ty) del(a[u]);
else add(a[u]);
for(int i=head[u];i;i=e[i].next){
v=e[i].to;
dfs1(v,ty);
}
}
void dfs2(int u){
int v;
for(int i=head[u];i;i=e[i].next){
v=e[i].to;
if(v==son[u]) continue;
dfs2(v);
dfs1(v,0);
}
if(son[u]) dfs2(son[u]);
for(int i=head[u];i;i=e[i].next){
v=e[i].to;
if(v==son[u]) continue;
dfs1(v,1);
}
add(a[u]);
if(mi==ma) ans++;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1,x;i<=n;i++){
cin>>a[i]>>x;
add_edge(x,i);
}
dfs0(1);
mi=1;
dfs2(1);
cout<<ans;
return 0;
}