zoukankan      html  css  js  c++  java
  • 洛谷P4332 [SHOI2014]三叉神经树(LCT)

    传送门

    FlashHu大佬太强啦%%%

    首先,我们可以根据每一个点的权值为$1$的儿子的个数把每个点记为$0~3$,表示这一个点的点权

    先考虑一下暴力的过程,假设从$0$变为$1$,先更改一个叶子结点,然后不断地往上更新,如果更改之后父亲的儿子中权值为$1$的儿子个数大于权值为$0$的儿子个数,那么就继续更新父亲,直到不能更新为止

    不难发现,我们每一个更改的都是树上的一条链。而且,只有当点权为$1$时,才能因为修改使点权变为$2$,使输出改变,从而更新祖先。那么,我们需要的就是对于每一个节点,从它向上的连续的点权为$1$的一部分

    如果是从$1$变为$0$同理,我们要维护从每一个节点向上的连续的点权为$2$的一部分

    那么我们对于每一个节点,先access,然后记录splay中最深的点权不为$1$和$2$的点,然后把它给splay到根,再对右子树进行区间修改,对他自己单点修改

    然后注意特判,如果整棵splay里都没有点权不为$1$或$2$的点,那么直接区间修改

    然后怎么记录点权嘞?我们先把所有叶子结点的值*2,那么只有0和2两种值,然后每一个节点只要加上它所有叶子结点的值/2就是这个点的点权了

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 using namespace std;
     6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     7 char buf[1<<21],*p1=buf,*p2=buf;
     8 inline int read(){
     9     #define num ch-'0'
    10     char ch;bool flag=0;int res;
    11     while(!isdigit(ch=getc()))
    12     (ch=='-')&&(flag=true);
    13     for(res=num;isdigit(ch=getc());res=res*10+num);
    14     (flag)&&(res=-res);
    15     #undef num
    16     return res;
    17 }
    18 char sr[1<<21];int C=-1;
    19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    20 inline void print(int x){
    21     sr[++C]=x|48,sr[++C]='
    ';
    22 }
    23 const int N=500005,M=1500005;
    24 int fa[M],ch[N][2],n1[N],n2[N],tag[N],v[M];
    25 int d[N],q[M],h=1,t,ans;
    26 #define ls ch[x][0]
    27 #define rs ch[x][1]
    28 inline bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    29 inline void pup(int x){
    30     //先右儿子再自己最后左儿子
    31     //因为&是短路运算符,有一个为假就会自动跳出 
    32     if(!(n1[x]=n1[rs])&&!(n1[x]=x*(v[x]!=1))) n1[x]=n1[ls];
    33     if(!(n2[x]=n2[rs])&&!(n2[x]=x*(v[x]!=2))) n2[x]=n2[ls];
    34 }
    35 inline void pdown(int x,int t){
    36     //被区间修改的要么都是1要么都是2,直接反转信息
    37     v[x]^=3,swap(n1[x],n2[x]),tag[x]+=t;
    38 }
    39 void all(int x){
    40     if(!isrt(x)) all(fa[x]);
    41     if(tag[x]) pdown(ls,tag[x]),pdown(rs,tag[x]),tag[x]=0;
    42 }
    43 void rotate(int x){
    44     int y=fa[x],z=fa[y],d=ch[y][1]==x;
    45     if(!isrt(y)) ch[z][ch[z][1]==y]=x;
    46     fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pup(y);
    47 }
    48 void splay(int x){
    49     all(x);
    50     for(int y=fa[x],z=fa[y];!isrt(x);y=fa[x],z=fa[y]){
    51         if(!isrt(y))
    52         ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y);
    53         rotate(x);
    54     }
    55     pup(x);
    56 }
    57 inline void access(int x){
    58     for(int y=0;x;x=fa[y=x])
    59     splay(x),rs=y,pup(x);
    60 }
    61 int main(){
    62 //    freopen("testdata.in","r",stdin);
    63     int n=read();
    64     for(int i=1;i<=n;++i)
    65     d[fa[read()]=fa[read()]=fa[read()]=i]=3;
    66     for(int i=n+1;i<=3*n+1;++i) v[q[++t]=i]=read()<<1;
    67     while(h<=t){
    68         int x=q[h++];if(x<=n) pup(x);
    69         v[fa[x]]+=v[x]>>1;
    70         if(!(--d[fa[x]])) q[++t]=fa[x];
    71     }
    72     ans=v[1]>>1;
    73     int q=read();
    74     while(q--){
    75         int x=read(),k=(v[x]^=2)-1;
    76         access(x=fa[x]),splay(x);
    77         if(~k?n1[x]:n2[x]){
    78             splay(x=(~k?n1[x]:n2[x]));
    79             pdown(rs,k),pup(rs);
    80             v[x]+=k,pup(x);
    81         }
    82         else pdown(x,k),pup(x),ans^=1;
    83         print(ans);
    84     }
    85     Ot();
    86     return 0;
    87 }
  • 相关阅读:
    Android开发入门经典【申明:来源于网络】
    Java 的局部变量和成员变量
    js数组基础知识链接
    mongodb学习笔记2
    docker离线安装
    mongodb学习笔记
    jupyter notebook安装
    执行docker ps命令挂住问题分析
    keras安装简介(windows)
    mybatis查询日期和log4j2配置
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9613787.html
Copyright © 2011-2022 走看看