[bzoj4551][TJOI&HEOI2016]树

题目大意

一颗树,除根节点外初始都是白点,根节点是黑点。
每次染黑一个结点或者询问一个结点的最近黑色祖先。

倒序处理

倒着做,于是每次是染白一个结点。
那么就并查集搞呀!

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100000+10;
struct dong{
    int x,ans;
    bool p;
} ask[maxn];
int fa[maxn],father[maxn],bz[maxn];
int h[maxn],go[maxn*2],next[maxn*2];
int i,j,k,l,t,n,m,tot;
char ch;
void add(int x,int y){
    go[++tot]=y;
    next[tot]=h[x];
    h[x]=tot;
}
void dfs(int x,int y){
    father[x]=y;
    int t=h[x];
    while (t){
        if (go[t]!=y) dfs(go[t],x);
        t=next[t];
    }
}
void dg(int x,int y){
    if (!bz[x]) fa[x]=father[x];
    int t=h[x];
    while (t){
        if (go[t]!=y) dg(go[t],x);
        t=next[t];
    }
}
int getfa(int x){
    return fa[x]?fa[x]=getfa(fa[x]):x;
}
char get(){
    char ch=getchar();
    while (ch!='Q'&&ch!='C') ch=getchar();
    return ch;
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,n-1){
        scanf("%d%d",&j,&k);
        add(j,k);add(k,j);
    }
    dfs(1,0);
    bz[1]=1;
    fo(i,1,m){
        ch=get();
        scanf("%d",&j);
        if (ch=='Q'){
            ask[i].p=1;
            ask[i].x=j;
        }
        else{
            ask[i].x=j;
            bz[j]++;
        }
    }
    dg(1,0);
    fd(i,m,1)
        if (ask[i].p) ask[i].ans=getfa(ask[i].x);
        else{
            bz[ask[i].x]--;
            if (!bz[ask[i].x]) fa[ask[i].x]=father[ask[i].x];
        }
    fo(i,1,m)
        if (ask[i].p) printf("%d\n",ask[i].ans);
}

你可能感兴趣的:([bzoj4551][TJOI&HEOI2016]树)