zoukankan      html  css  js  c++  java
  • 洛谷4322 SHOI2014 三叉神经树(LCT+思维)

    好久之前做的题了QWQ
    现在来补一发博客

    一道神仙题啊。。qwq

    首先,我们可以看出来,我们如果对于每个点维护一个(val),表示他的直系儿子中有几个表现为1的。

    那么(val[x]>>1) 就是他反应的类型

    这样十分便于我们计算一开始的(val)

    那么考虑修改。

    一定是会修改一条(连续1(对应着0->1),或者连续2(1->0))

    也就是说,如果我们能够知道一次修改,(1到x)的路径下最下面的1或者2的位置,我们就能够通过链修改来实现。

    其实一开始我想的是二分

    我们发现,可以通过(LCT)维护最深的不是(1)的位置和不是(2)的位置(num1和num2)

    那么我们对于一次修改,假设由(0修改成1)
    如果(num1==0),那么说明整条链都会被修改,直接修改整条路径

    不然,我们就将路径提出来,(splay(num1))之后,修改他的右儿子,表示他下面的点。
    然后把当前点的(val)修改,但是不改变别的量。

    QWQ有一些细节,对于修改的时候,由于路径上的(val)都是1或者2。
    所以修改的之后可以直接(xor 2)

    具体细节看代码实现吧

    里面有详细的注释

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<set>
    using namespace std;
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    const int maxn = 2e6+1e2;
    int ch[maxn][3];
    int fa[maxn],val[maxn];
    int tag[maxn];
    int n,m;
    int num1[maxn],num2[maxn]; //深度最深的 儿子数不为1 或者 2 的 节点是的编号 
    int st[maxn];
    int son(int x)
    {
     if (ch[fa[x]][0]==x) return 0;
     else return 1;
    }
    bool notroot(int x)
    {
     return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
    }
    void update(int x) //由于是深度最深,我们一定是先考虑右子树,再说当前点,再是右子树 
    {
     num1[x]=num1[ch[x][1]];
     if (!num1[x] && val[x]!=1) num1[x]=x;
     if (!num1[x]) num1[x]=num1[ch[x][0]];
     num2[x]=num2[ch[x][1]];
     if (!num2[x] && val[x]!=2) num2[x]=x;
     if (!num2[x]) num2[x]=num2[ch[x][0]];
    }
    void solve(int x,int d)
    {
     val[x]^=3;
     swap(num1[x],num2[x]); //修改的时候,必定是一段全为1或者2的区间,所以一个一定是0,直接交换是没错的 
     tag[x]+=d;
    }
    void pushdown(int x)
    {
     if (tag[x])
     {
      if (ch[x][0]) solve(ch[x][0],tag[x]);
      if (ch[x][1]) solve(ch[x][1],tag[x]);
      tag[x]=0;
     }
    }
    void rotate(int x)
    {
     int y=fa[x],z=fa[y];
     int b=son(x),c=son(y);
     if (notroot(y)) ch[z][c]=x;
     fa[x]=z;
     ch[y][b]=ch[x][!b];
     fa[ch[x][!b]]=y;
     ch[x][!b]=y;
     fa[y]=x;
     update(y);
     update(x);
    }
    void splay(int x)
    {
     int y=x,cnt=0;
     st[++cnt]=y;
     while (notroot(y)) y=fa[y],st[++cnt]=y;
     while (cnt) pushdown(st[cnt--]);
     while (notroot(x))
     {
      int y=fa[x],z=fa[y];
      int b=son(x),c=son(y);
      if (notroot(y))
      {
       if (b==c) rotate(y);
       else rotate(x);
      }
      rotate(x);
     }
        update(x);
    }
    void access(int x)
    {
     for (int y=0;x;y=x,x=fa[x])
     {
      splay(x);
      ch[x][1]=y;
      update(x);
     }
    }
    int in[maxn];
    queue<int> q;
    int main()
    {
       n=read();
       for (int i=1;i<=n;i++)
       {
          int x=read(),y=read(),w=read();     
          in[i]=3;
          fa[x]=fa[y]=fa[w]=i; 
       }
       for (int i=n+1;i<=3*n+1;i++) val[i]=read()*2,q.push(i); //我们事先val都*2,那么对于每个点,他表现出来的特征就是val>>1 
       int m=read();
       while (!q.empty()) //拓扑排序先预处理出来每个点的val 
       {
          int x=q.front();
          q.pop();
          if (x<=n) update(x);
          val[fa[x]]+=val[x]/2;
          in[fa[x]]--;
          if (!in[fa[x]]) q.push(fa[x]);
       }
       int ans=val[1]>>1;
       //在本题中,val表示儿子的表示1的数量,那么val>>1就相当于每个点表达的信息
       for (int i=1;i<=m;i++)
       {
          int x=read();
          val[x]^=2; //叶子节点只有可能是0或者1,而乘2之后就是0或者2 
          int k = val[x] - 1;
          x=fa[x]; //不修改底下的叶子节点 
          access(x);
          splay(x); //打通这个点到1的路径 
          int now;
          if (k==-1) now = num2[x];
          else now = num1[x];
          if (!now)
          {
              solve(x,k);
              update(x);
              ans^=1;
       }
       else
       {
         splay(now);
         solve(ch[now][1],k); 
         update(ch[now][1]);
       val[now]+=k;
         update(now);
       }
       cout<<ans<<"
    ";
       }
       return 0;
    }
    
    
  • 相关阅读:
    type( ) 和 isinstance( )
    el-input-number element计数器设置自定义小数位数
    Electron-Vue起步
    SmartGit破解使用的个人方法
    js 之 数组去重
    Vue动态class
    vue项目如何(友好的)刷新当前页
    Promise()与链式执行
    Vue过渡&循环切换&放大缩小动画
    css Margin塌陷问题(margin属性撑不开盒子)
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161940.html
Copyright © 2011-2022 走看看