给一颗n个节点的树,每个节点上有一个颜色值,1为根节点。有m次询问,每次询问以vj为顶点的子树下颜色数量超过kj个的颜色总共有多少种。
考虑树上启发式合并。
首先将询问保存。每次加入新的节点的时候会把这个节点的颜色值+1,考虑我们把这个节点的颜色值的数量在树状数组中减去1,然后这个颜色值数量+1,在树状数组中更新新的颜色值数量。
删除节点同理。
#include <bits/stdc++.h> using namespace std; const int M = 1e5+7; int n,m,c[M],head[M],cnt,t[M],tot[M],sz[M],son[M],ans[M]; vector<pair<int,int> > vec[M]; struct edge{ int v,next; }e[M<<1]; void init(){ cnt=0;memset(head,-1,sizeof(head)); memset(t,0,sizeof(t)); memset(tot,0,sizeof(tot)); } void add(int u,int v){ e[++cnt].v=v;e[cnt].next=head[u]; head[u]=cnt; } void update(int x,int y){ for(;x<=M;x+=x&(-x)){ t[x]+=y; } } int query(int x){ int aa=0; for(;x;x-=x&(-x)){ aa+=t[x]; } return aa; } void dfs(int u,int fa){ sz[u]=1;son[u]=-1; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; dfs(v,u); sz[u]+=sz[v]; if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v; } return ; } void addnode(int u){ if(tot[c[u]]) update(tot[c[u]],-1); tot[c[u]]++; update(tot[c[u]],1); } void delnode(int u){ update(tot[c[u]],-1); tot[c[u]]--; if(tot[c[u]]) update(tot[c[u]],1); } void addtree(int u,int fa){ addnode(u); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; addtree(v,u); } } void deltree(int u,int fa){ delnode(u); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; deltree(v,u); } } void dsu(int u,int fa){ for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa||v==son[u]) continue; dsu(v,u); deltree(v,u); } if(son[u]!=-1) dsu(son[u],u); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa||v==son[u]) continue; addtree(v,u); } addnode(u); for(int i=0;i<vec[u].size();i++){ int v=vec[u][i].first,k=vec[u][i].second; ans[k]=query(100001)-query(v-1); } } int main(){ init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v);add(v,u); } for(int i=1;i<=m;i++){ int u,k; scanf("%d%d",&u,&k); vec[u].push_back(make_pair(k,i)); } dfs(1,-1); dsu(1,-1); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }