hdu 4358 Boring counting
题意就是给一颗有根树再给m个询问,每个询问需要回答第i个节点的子树下有多少个出现k次的数字。
考虑启发式合并,当加入一个节点时如果加入之前是k次那么加入之后答案-1,如果加入后刚好是k次,那么答案+1。
删除操作同理。
#include <bits/stdc++.h> using namespace std; const int M = 1e5+7; int _,n,a[M],head[M],cnt,sz[M],son[M],k,ans[M],q,cas=1,tmp,flag=0; map<int,int> mp; struct edge{ int v,next; }e[M<<1]; void init(){ tmp=cnt=0;memset(head,-1,sizeof(head)); mp.clear();memset(ans,0,sizeof(ans)); } void add(int u,int v){ e[++cnt].v=v;e[cnt].next=head[u]; head[u]=cnt; } 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(mp[a[u]]==k) tmp-=1; if(mp[a[u]]+1==k) tmp+=1; mp[a[u]]++; } void delnode(int u){ if(mp[a[u]]==k) tmp-=1; if(mp[a[u]]-1==k) tmp+=1; mp[a[u]]--; } 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); ans[u]=tmp; } int main(){ scanf("%d",&_); while(_--){ if(flag) printf("\n"); flag=1; init(); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v);add(v,u); } dfs(1,-1); dsu(1,-1); scanf("%d",&q); printf("Case #%d:\n",cas++); while(q--){ int u; scanf("%d",&u); printf("%d\n",ans[u]); } } return 0; }

浙公网安备 33010602011771号