1. 程式人生 > >HDU 5927 Auxiliary Set (dfs+lca)

HDU 5927 Auxiliary Set (dfs+lca)

題意:

給出一個樹,和一個點集,點集外的點為“重要的點”,如果某個點集內的點是兩個“重要的點的LCA”,那麼它也是“重要的點”,其他點為“非重要的點”。  求出重要的點的個數。 

分析:

其實對於每一個詢問我們只要判斷哪些不重要的點是能進入集合的,那麼對於一個不重要的點x,怎樣才能進入集合呢?我們先dfs對於所有的點求出fa[x]和son[x]。當詢問是,我們先初始確定每個不重要的點的son'[x],如果一個點要進入集合那麼顯然要求son'[x]>=2,這樣才會有兩個重要的點的最近公共祖先是x。那麼對於一個點x的son'又會受什麼影響呢?當一個點y滿足son'[y]==0&&y是不重要的點那麼son'[fa[y]]--。這樣我們就能維護我們需要的資訊了。O(mlogm) 

#include<bits/stdc++.h>

using namespace std;

const int maxn=2e5+10;

int dep[maxn];
int fa[maxn];
int son[maxn];
int son_[maxn];
int d[maxn];

int head[maxn];
int tot;

struct node{
    int to;
    int next;
}g[maxn];

void addedge(int u,int v){
    g[tot].to=v;
    g[tot].next=head[u];
    head[u]=tot++;
}

void dfs(int v,int pre){
    fa[v]=pre;
    dep[v]=dep[pre]+1;
    son[v]=0;
    for(int i=head[v];~i;i=g[i].next){
        if(g[i].to!=pre){
            dfs(g[i].to,v);
            son[v]++;
        }
    }
}

bool cmp(int a,int b){
    return dep[a]>dep[b];
}

void init(){
    memset(head,-1,sizeof head);
    tot=0;
    dep[0]=0;
}

int main(){
    int T;
    scanf("%d",&T);
    for(int cs=1;cs<=T;cs++){
        init();
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=0;i<n-1;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs(1,0);
        printf("Case #%d:\n",cs);
        while(q--){
            int m;
            scanf("%d",&m);
            int ans=n-m;
            for(int i=0;i<m;i++){
                scanf("%d",&d[i]);
            }
            sort(d,d+m,cmp);
            for(int i=0;i<m;i++) son_[d[i]]=son[d[i]];
            for(int i=0;i<m;i++){
                if(son_[d[i]]>=2) ans++;
                else if(son_[d[i]]==0) son_[fa[d[i]]]--;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}