[SHOI2014] 三叉神经树

题意:

给你一个有$n$个非叶节点的完满三叉树(每个点要么有三个儿子要么没有儿子)。

那么显然这棵树共有$2n+1$个叶节点。每个叶节点有一个0/1的权值。

每个非叶节点的权值等于它的儿子中权值的众数,也就是儿子的权值和/2。

现在有$q$次修改,每次将一个叶子的权值取反,问每次修改之后根节点的权值是什么。

$n,q\leq 5\times 10^{5}$。

 

题解:用$LCT$维护一条链上最深的不符合要求的元素。

看到这题我首先写了一个$O(nlog^{2}n)$的树剖,然后过了。

完。

我们令一个点的权值等于它所有儿子的原权值之和。

那么修改一个叶子影响的其实是从它到它上面第一个点权不是1/2的点。

于是我们就有一个$O(nlog^{2}n)$树剖的做法:

维护链上权值最小/最大值,每次从修改的叶子往上跳,跳到第一个不符合要求的链时二分终点位置。

但由于这是一道$LCT$练习题,我们可以考虑用$LCT$来维护这个东西。

只需要对于$Splay$的每个点维护它的子树内最深的不为1/2的点是哪个点即可。

由于$Splay$以深度为关键字我们甚至不需要记录原树上每个点的深度。

由于修改只有将1变成2,将2变成1,我们甚至不需要记录其他权值。

每次修改时将从根到$x$这条链上最深的不为1/2的点转到根,然后修改根的右子树即可。

时间复杂度$O(nlogn)$。

 

代码:

#include<bits/stdc++.h>
#define maxn 500005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long
#define ls c[u][0]
#define rs c[u][1]
#define debug(x) cerr<<#x<<": "<<x<<endl
#define fgx cerr<<"--------------"<<endl
#define dgx cerr<<"=============="<<endl

using namespace std;
int n,cc[maxn][3],f[maxn*3],val[maxn*3],lz[maxn];
int n1[maxn],n2[maxn],st[maxn],c[maxn][2];

inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline void dfs(int u){
    for(int i=0;i<3;i++) 
        if(cc[u][i]<=n) 
            dfs(cc[u][i]),val[u]+=(val[cc[u][i]]>1);
    return;
}
inline bool nroot(int u){return c[f[u]][0]==u||c[f[u]][1]==u;}
inline bool gc(int u){return c[f[u]][1]==u;}
inline void pdr(int u,int v){val[u]+=v,lz[u]+=v,swap(n1[u],n2[u]);}
inline void pd(int u){if(lz[u]) pdr(ls,lz[u]),pdr(rs,lz[u]),lz[u]=0;}
inline void pu(int u){
    if(n1[rs]) n1[u]=n1[rs]; else if(val[u]!=1) n1[u]=u; else n1[u]=n1[ls];
    if(n2[rs]) n2[u]=n2[rs]; else if(val[u]!=2) n2[u]=u; else n2[u]=n2[ls];
}
inline void rotate(int u){
    int v=f[u],w=f[v],t1=gc(u),t2=gc(v),s=c[u][t1^1];
    c[v][t1]=s; if(s)f[s]=v;
    if(nroot(v)) c[w][t2]=u;f[u]=w;
    c[u][t1^1]=v,f[v]=u;
    pu(v),pu(u),pu(w);
}
inline void splay(int u){
    int p=0,v=u; st[++p]=v; 
    while(nroot(v)) st[++p]=(v=f[v]); 
    while(p) pd(st[p--]); 
    for(v=f[u];nroot(u);rotate(u),v=f[u]) 
        if(nroot(v)) rotate((gc(u)==gc(v))?v:u); 
}
inline void access(int u){for(int v=0;u;u=f[v=u]) splay(u),rs=v,pu(u);}

int main(){
    n=read();
    for(int u=1;u<=n;u++) 
        for(int i=0;i<3;i++) 
            f[cc[u][i]=read()]=u;
    for(int u=n+1;u<=3*n+1;u++) 
        val[f[u]]+=(val[u]=read());
    dfs(1); 
    for(int u=1;u<=n;u++){
        if(val[u]!=1) n1[u]=u; 
        if(val[u]!=2) n2[u]=u;
    }
    int Q=read();
    while(Q--){
        int u=read(); val[u]^=1;
        if(val[u]){
            u=f[u],access(u),splay(u); 
            if(!n1[u]) pdr(u,1); 
            else u=n1[u],splay(u),pdr(rs,1),val[u]++,pu(u);
        }
        else{
            u=f[u],access(u),splay(u); 
            if(!n2[u]) pdr(u,-1); 
            else u=n2[u],splay(u),pdr(rs,-1),val[u]--,pu(u);
        }
        splay(1),printf("%d\n",(val[1]>1));
    }
    return 0;
}
三叉神经树
posted @ 2019-12-07 14:37  Fugtemypt  阅读(315)  评论(0编辑  收藏  举报