Qtree 6-LCT

题意

给你一棵n个点的树,编号1~n,共m次操作。每个点可以是黑色,可以是白色。初始时所有点都是黑色。下面有两种操作:
0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥有相同的颜色
1 u:翻转u的颜色


数据范围

1 n , m 10 5


题解

先建两颗树分别维护两种颜色。保证同色的结点只有在对应颜色的lct内才连通。
对于每个翻转操作,如果真的一条一条边的修改,就gg了。
所以对于每个节点,我们把他的父边看做真正的结点,这样做的效果是,对于每个联通块,除了该联通快的根节点以外的结点,都为同色。那么翻转一个点,需要在它所在颜色中断开它的父边,在另一颜色的lct中连上即可。
对于根节点再加一个父亲就好了。每次查询回答该连通块根节点的右儿子的size即可。


代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1e5+10;
int n,m,p[N],col[N];
int head[N],to[N<<1],nxt[N<<1],tot;
inline int rd()
{
    char ch=getchar();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}

inline void lkk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

struct T{
    int c[N][2],s[N],su[N],f[N];
    T(){for(int i=1;i<N;++i) s[i]=1;}
    bool isrt(int x){return (c[f[x]][0]!=x) && (c[f[x]][1]!=x);}
    void update(int x){s[x]=s[c[x][0]]+s[c[x][1]]+1+su[x];}
    void rotate(int x){
        int y=f[x],z=f[y],gs=c[y][1]==x;f[x]=f[y];
        if(!isrt(y)) c[z][c[z][1]==y]=x;
        c[y][gs]=c[x][gs^1];f[c[x][gs^1]]=y;
        c[x][gs^1]=y;f[y]=x;update(y);
    }
    void splay(int x){
        int y,z;
        while(!isrt(x)){
            y=f[x];z=f[y];
            if(!isrt(y)) (c[z][1]==y)^(c[y][1]==x)?rotate(x):rotate(y);
            rotate(x);
        }
        update(x);
    }
    void access(int x){
        for(int y=0;x;x=f[x]){
            splay(x);
            su[x]+=s[c[x][1]];
            su[x]-=s[y];c[x][1]=y;
            y=x;
        }
    }
    int fdrt(int x){
        access(x);splay(x);
        for(;c[x][0];x=c[x][0]);
        splay(x);
        return x;
    }
    void lk(int x){
        access(x);splay(x);
        f[x]=p[x];
        access(f[x]);splay(f[x]);
        s[f[x]]+=s[x];su[f[x]]+=s[x];
    }
    void cut(int x){
        access(x);splay(x);
        f[c[x][0]]=0;c[x][0]=0;
        update(x);
    }
    int query(int x){
        x=fdrt(x);
        return s[c[x][1]];
    }
}lct[2];

inline void dfs(int x)
{
    for(int j,i=head[x];i;i=nxt[i]){
        j=to[i];
        if(j!=p[x]){
            p[j]=x;dfs(j);lct[0].lk(j);
        }
    }
}

int main(){
    int i,op,x,y;
    n=rd();
    for(i=1;i<n;++i){x=rd();y=rd();lkk(x,y);lkk(y,x);}
    dfs(1);p[1]=n+1;lct[0].lk(1);
    m=rd();
    while(m--){
        op=rd();x=rd();
        if(op)
        {lct[col[x]].cut(x);col[x]^=1;lct[col[x]].lk(x);}
        else printf("%d\n",lct[col[x]].query(x));
    }
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80725722