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;
}
View Code

 

posted @ 2018-08-27 09:36  LMissher  阅读(107)  评论(0)    收藏  举报