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

    [SHOI2014]三叉神经树 

    不是那么裸的LCT题

    基本凭借一己之力AC了此题(多亏了标签+std对拍)

    分析性质

    自底向上进行0/1的修改

    一定是修改的自底向上的一段链!

    并且这些点的儿子之前都是恰好本身的颜色儿子多一个

    可以整链找到最上面的不能更新的点,然后整链打标记

    但是,扣去某个儿子剩下的儿子的sz0和sz1不好直接处理

    LCT可以从1,access(x)劈出一条实链,不妨这个链上的儿子不进行统计,只统计虚儿子!

    sz0==sz1都是临界的。就可以了

    具体:

    LCT维护:fa,child[0/1]

    id[0/1]表示找0/1来讲最深的不好的点(不满足sz0=sz1的0/1点或者本身颜色是1/0的)(最浅好点还不能跨过不好点,麻烦)

    tag,翻转颜色标记

    mx,所在实链最深点,便于直接更新id[0/1](数据水,没必要233333)

    wrk函数,access,splay,找到id[]=y,如果有,splay(y),tag右儿子

    否则,splay(1),tag(1),colort^=1;

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=1500000+5;
    int n,q;
    struct node{
        int ch[2],fa;
        int co;
        int lsz[2];
        int mx;//zui shen dian
        int id[2];//deepest nogood point
        int tag;
        bool nogood(int c){
            return (co!=c)||(co==c&&lsz[c]>=2);
        }
        void op(){
            cout<<" ch[0] "<<ch[0]<<" ch[1] "<<ch[1]<<endl;
            cout<<" lsz[0] "<<lsz[0]<<" lsz[1] "<<lsz[1]<<endl;
            cout<<" id[0] "<<id[0]<<" id[1] "<<id[1]<<endl;
            cout<<" co "<<co<<endl;
        }
    }t[N];
    bool nrt(int x){
        return t[t[x].fa].ch[0]==x||t[t[x].fa].ch[1]==x;
    }
    void pushup(int x){
        if(t[x].ch[1]&&t[t[x].ch[1]].id[0]){
            t[x].id[0]=t[t[x].ch[1]].id[0];
        }else if(t[x].nogood(0)){
            t[x].id[0]=x;
        }else if(t[x].ch[0]&&t[t[x].ch[0]].id[0]){
            t[x].id[0]=t[t[x].ch[0]].id[0];
        }else t[x].id[0]=0;
        
        if(t[x].ch[1]&&t[t[x].ch[1]].id[1]){
            t[x].id[1]=t[t[x].ch[1]].id[1];
        }else if(t[x].nogood(1)){
            t[x].id[1]=x;
        }else if(t[x].ch[0]&&t[t[x].ch[0]].id[1]){
            t[x].id[1]=t[t[x].ch[0]].id[1];
        }else t[x].id[1]=0;
        
        if(t[x].ch[1]) t[x].mx=t[t[x].ch[0]].mx;
        else t[x].mx=x;
    }
    void tag(int x){
        t[x].tag^=1;
        //if(x<=n) 
        t[x].co^=1;
        t[x].id[t[x].co]=0;
        t[x].id[t[x].co^1]=t[x].mx;
    }
    void pushdown(int x){
        if(t[x].tag){
            tag(t[x].ch[0]);
            tag(t[x].ch[1]);
            t[x].tag=0;
        }
    }
    void rotate(int x){
        int y=t[x].fa,d=t[y].ch[1]==x;
        t[t[y].ch[d]=t[x].ch[!d]].fa=y;
        if(nrt(y)) t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[1]==y]=x;
        else t[x].fa=t[y].fa;
        t[t[x].ch[!d]=y].fa=x;
        pushup(y);
    }
    int sta[N];
    void splay(int x){
        int z=0,y=x;
        sta[++z]=y;
        while(nrt(y)) y=t[y].fa,sta[++z]=y;
        while(z) pushdown(sta[z--]);
        while(nrt(x)){
            y=t[x].fa,z=t[y].fa;
            if(nrt(y)){
                rotate((t[y].ch[0]==x)==(t[z].ch[0]==y)?y:x);
            }
            rotate(x);
        }
        pushup(x);
    }
    int bac(int x){
        if(!t[x].ch[1]) return 0;
        pushdown(x);
        x=t[x].ch[1];while(t[x].ch[0]) pushdown(x),x=t[x].ch[0];return x;
    }
    int pre(int x){
        pushdown(x);
        while(t[x].ch[0]) pushdown(x),x=t[x].ch[0];return x;
    }
    void access(int x){
    //    cout<<" access "<<x<<endl;
        for(reg y=0;x;y=x,x=t[x].fa){
    //        cout<<" x "<<x<<"  y "<<y<<endl;
            splay(x);
            int pr=pre(y),bc=bac(x);
            if(pr) t[x].lsz[t[pr].co]--;
            if(bc) t[x].lsz[t[bc].co]++;
    //        cout<<" pre "<<pr<<" bac "<<bc<<endl;
            t[x].ch[1]=y;
            pushup(x);
    //        t[x].op();
        }
    }
    int cort;
    void wrk(int x,int c){
        access(x);
        splay(x);
    //    cout<<"splyaxx "<<endl;
    //    t[x].op();
        if(t[x].id[c^1]){
            int y=t[x].id[c^1];
    //        cout<<" -------------change "<<y<<endl;
            splay(y);
            tag(t[y].ch[1]);
        }else{
    //        cout<<"************-changert"<<endl;
            cort=c;
            splay(1);
            tag(1);
    //        t[1].op();
        }
    }
    int    col[N];
    struct edge{int nxt,to;}e[2*N];int hd[N],cnt;
    void add(int x,int y){e[++cnt].nxt=hd[x];e[cnt].to=y;hd[x]=cnt;}
    void dfs(int x){
        for(reg i=hd[x];i;i=e[i].nxt){dfs(e[i].to);t[x].lsz[t[e[i].to].co]++;t[e[i].to].fa=x;}
        if(t[x].lsz[1]>t[x].lsz[0]) t[x].co=1;
    }
    
    int main(){
        rd(n);
        int x;
        for(reg i=1;i<=n;++i){
            rd(x);add(i,x);rd(x);add(i,x);rd(x);add(i,x);
        }
        for(reg i=n+1;i<=3*n+1;++i) rd(col[i]),t[i].co=col[i];
        dfs(1);
        for(reg i=1;i<=n;++i) pushup(i);//to make id
    //    for(reg i=1;i<=n;++i){
    //        cout<<i<<" : ";
    //        t[i].op();
    //        cout<<endl;
    //    }
        rd(q);
        cort=t[1].co;
    //    cout<<" pre cort "<<cort<<endl;
        while(q--){
            rd(x);wrk(x,col[x]^1);col[x]^=1;
            printf("%d
    ",cort);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/3/14 17:06:41
    */

    pushdown注意更新全部的信息!,id[0/1]必须考虑到

    直接ch相连不一定是实际相连的。

    额外记录的col主函数中是要变的。因为可能不能实时pushdown

    写法有些毒瘤。。。。

    FlashHu提供一种简单多的方法:

    就是记录点权0/1/2/3,即颜色为1的儿子个数

    找自底向上极长的连续1/2点权的链,都变成1/0颜色

    如果:

    不可能更新到那个1的儿子,因为那个1的点权至少是2,所以没有问题!

    然后,就成静态的了。。。。

    LCT、树剖就随便做了。。。。。。

  • 相关阅读:
    VS插件哪家强?CodeRush v20.2帮你忙
    WinForms界面开发工具DevExpress WinForms v20.2亮点——全新Sankey Diagram控件震撼发布
    java中将信息写入excel
    java中使用IO流将以文件中的内容去取到指定的文件中
    java中使用IO流复制文件
    采购订单写入sap失败后,抛出自定义异常,回滚数据库
    java中将文件夹里面的文件复制到指定的文件夹(java IO)
    JAVA中IO流详解
    获取员工合同信息列表 定时任务
    Java连接MySQL数据库——含步骤和代码
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10533257.html
Copyright © 2011-2022 走看看