[Spoj16549]Qtree6

题意:询问与 u u 相同颜色的联通块的大小,带修改

考虑建立黑白两颗lct,答案就是在相应 lct l c t 中, u u 所属的那棵树的大小了

至于修改的话一个非常暴力的想法就是直接cut然后 link l i n k

这样的话碰到菊花图就 GG G G 了(下面我们讨论维护黑树的 lct l c t ,白树同理)

考虑到原树的形态是不会变的,所以我们可以设在 lct l c t 中如果有边 edge(u,v) e d g e ( u , v ) ,那么 v v 就是黑色(u不一定是黑色)

这样的话我们 cut c u t link l i n k 都只要管 edge(u e d g e ( u 原树中的父亲, u) u ) 这条边了

统计答案的话就把它 access a c c e s s 上去后然后判断这条链最上面的那个点是不是黑点,不是就要输出最上面那个点的儿子节点

要是不会 lct l c t 维护子树信息可以先做做这个题目

然后这题因为只要 link,cut l i n k , c u t egde(fa[u],u) e g d e ( f a [ u ] , u ) 这条边所以写法可以特殊一点

具体怎么特殊看代码

#include<bits/stdc++.h>
#define fp(i,a,b) for(int i=a,I=b;i<=I;++i)
#define go(i,u) for(int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c^48;
    while(c=gc(),47<c&&c<58)x=(x<<1)+(x<<3)+(c^48);x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
typedef int arr[N];
struct eg{int nx,to;}e[N<<1];
int n,m,ce;arr fi,fa,sz,col;
struct LCT{
    int Col,ch[N][2];arr fa,sz,tp;
    #define lc(u)(ch[u][0])
    #define rc(u)(ch[u][1])
    inline void op(int u,int w){sz[u]+=w,tp[u]+=w;}
    inline bool ir(int u){return lc(fa[u])^u&&rc(fa[u])^u;}
    inline bool gf(int u){return rc(fa[u])==u;}
    inline void up(int u){sz[u]=sz[lc(u)]+sz[rc(u)]+tp[u];}
    inline void rot(int u){
        int p=fa[u],k=gf(u);
        if(!ir(p))ch[fa[p]][gf(p)]=u;
        if(ch[u][!k])fa[ch[u][!k]]=p;
        ch[p][k]=ch[u][!k],ch[u][!k]=p;
        fa[u]=fa[p],fa[p]=u,up(p);
    }
    void splay(int u){
        for(int f=fa[u];!ir(u);rot(u),f=fa[u])
            if(!ir(f))rot(gf(u)==gf(f)?f:u);
        up(u);
    }
    inline void acc(int u){for(int v=0;u;u=fa[v=u])splay(u),tp[u]+=sz[ch[u][1]]-sz[v],ch[u][1]=v,up(u);}
    inline void brt(int u){acc(u),splay(u);}
    inline void link(int u,int v){
        if(!v)return;
        brt(v),splay(u),tp[fa[u]=v]+=sz[u];
    }
    inline void cut(int u,int v){
        if(!v)return;
        brt(u),fa[lc(u)]=0,lc(u)=0,up(u);
    }
    inline int Gf(int u){brt(u);while(lc(u))u=lc(u);return u;}
    inline int qry(int u){
        int p=Gf(u);splay(p);
        return col[p]==Col?sz[p]:sz[ch[p][1]];
    }
}T[2];
inline void add(int u,int v){e[++ce]=eg{fi[u],v},fi[u]=ce;}
void dfs(int u){sz[u]=1;go(i,u)if(v!=fa[u])T[0].fa[v]=fa[v]=u,dfs(v),sz[u]+=sz[v];}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    sd(n),T[1].Col=1;int u,v;
    fp(i,2,n)sd(u),sd(v),add(u,v),add(v,u);
    dfs(1);sd(m);fp(i,1,n)T[0].tp[i]=T[0].sz[i]=sz[i];
    while(m--){
        sd(v),sd(u);int&c=col[u];
        if(v)T[c].cut(u,fa[u]),T[c].op(u,-1),c^=1,T[c].op(u,1),T[c].link(u,fa[u]); 
        else we(T[c].qry(u));
    }
return Ot(),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值