zoukankan      html  css  js  c++  java
  • [SHOI2014] 三叉神经树

    题意:

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

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

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

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

    $n,qleq 5 imes 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
    ",(val[1]>1));
        }
        return 0;
    }
    三叉神经树
  • 相关阅读:
    Kafk为什么这么快
    kafka消息格式演变
    kafka基础命令及api使用
    zookeeper && kafka && kafka manager开机自启动设置
    sqoop进行将Hive 词频统计的结果数据传输到Mysql中
    hive实例的使用
    使用HBase Shell命令
    Hadoop使用实例 词频统计和气象分析
    HDFS 操作命令
    第四次作业 描述HDFS体系结构、工作原理与流程
  • 原文地址:https://www.cnblogs.com/YSFAC/p/12001653.html
Copyright © 2011-2022 走看看