zoukankan      html  css  js  c++  java
  • 【数据结构】——SHOI2014 三叉神经树

    第一次写黑题,好紧张(bushi)


    (图片从洛谷上截的)

      这道题可以说是一道LCT的练手题,首先对于题目中给出的树,如果我们改变一个叶子节点的值,那么影响范围是它的父节点,如果父节点改变了,那么爷爷节点也可能会改变,那么我们猜想,是否存在一段连锁的改变呢?

      显然,如果用0/1/2/3表示一个节点的状态,即儿子含有数字1的个数,那么对于由浅到深的一段1/0/1/1/0中,最深的一个0节点变为了1,那么序列就会变为:1/1/2/2/1,至多影响到浅层的那个0节点。

      如果考虑到由1变为0,其实是一个道理,(这里连锁的是2)因此,我们考虑维护一段自底向上的区间,满足含有一段连续的1/2,直到出现一个不为1/2的点,然后修改区间,再单独修改那个点,就完成了维护。

      具体的说,我们先打通题目给的点x,打通路径,再查找最深的那个不为1/2的节点,进行修改,其中有些小技巧:

      1.叶子节点乘以2,树枝等于叶子节点之和除以2,这样会方便些。

      2.向上更新的步骤:因为splay维护的是深度,所以从右->自己->左的顺序最好,分别判断一下。

      3.向下传递的步骤:实质就是将区间上的每个1变为2,2变为1,将值异或3即可,同时要交换x的维护数组num1,num2(因为这个时候一段1的序列会全部变为2,等于是同时在维护一段2序列了

      4.注意卡常,把inline啊register int啊还有什么快读都开了,时间从4.2s直降到200ms。

      5.我被内存坑惨了,开正常大小会出各种WA,RE,MLE啥的,就开大了几倍,全变TLE了,以后开数组大小要根据题目给的要求尽量开大点。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define rs c[x][1]
      4 #define ls c[x][0]
      5 const int N=2e6+5;
      6 int n;
      7 int f[N],cnt,sum[N],q,tot,head[N],aa,bb,cc,ans;
      8 int c[N][2],st[N],num2[N],num1[N],tag[N];
      9 inline int read()
     10 {
     11    int ans = 0,op = 1;char ch = getchar();
     12    while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
     13    while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
     14    return ans * op;
     15 }
     16 struct edge{
     17     int next,to;
     18 }e[N<<1];
     19 void addedge(int from,int to){
     20     e[++cnt].to=to;
     21     e[cnt].next=head[from];
     22     head[from]=cnt;
     23 }
     24 void dfs(int u){
     25     for(int i=head[u];i;i=e[i].next){
     26         dfs(e[i].to);
     27         sum[u]+=(sum[e[i].to]>>1);
     28     }
     29 }
     30 int nroot(int x){
     31     return c[f[x]][0]==x||c[f[x]][1]==x;
     32 }
     33 void pushup(int x){
     34     num1[x]=num1[rs];
     35     if(!num1[x]&&sum[x]!=1) num1[x]=x;
     36     if(!num1[x]) num1[x]=num1[ls];
     37     num2[x]=num2[rs];
     38     if(!num2[x]&&sum[x]!=2) num2[x]=x;
     39     if(!num2[x]) num2[x]=num2[ls];
     40 }
     41 void pusm(int x,int d){
     42     sum[x]^=3;
     43     swap(num1[x],num2[x]);
     44     tag[x]+=d;
     45 }
     46 void pushdown(int x){
     47     if(nroot(x)) pushdown(f[x]);
     48     if(tag[x]){
     49         pusm(ls,tag[x]);
     50         pusm(rs,tag[x]);
     51         tag[x]=0;
     52     } 
     53 }
     54 void rotate(int x){
     55     int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][k^1];
     56     if(nroot(y)) c[z][c[z][1]==y]=x; 
     57     c[x][k^1]=y;
     58     c[y][k]=w;
     59     if(w) f[w]=y;
     60     f[y]=x;
     61     f[x]=z;
     62     pushup(y);
     63     
     64 }
     65 void splay(int x){
     66     pushdown(x);
     67     int y=x,z=0;
     68     st[++z]=y;
     69     while(nroot(y)) st[++z]=y=f[y];
     70     while(z) pushdown(st[z--]);
     71     while(nroot(x)){
     72         y=f[x],z=f[y];
     73         if(nroot(y)) rotate((c[y][0]==x)^(c[z][0]==y)?x:y);
     74         rotate(x);
     75     }
     76     pushup(x);
     77 }
     78 void access(int x){
     79     for(int g=0;x;x=f[g=x]){
     80         splay(x);
     81         rs=g;
     82         pushup(x);
     83     }
     84 }
     85 int main(){
     86 //    freopen("neuron.in","r",stdin);
     87 //    freopen("neuron.out","w",stdout);
     88     n=read();
     89     int i;
     90     for(i=1;i<=n;i++){
     91         aa=read(),bb=read(),cc=read();
     92         f[aa]=f[bb]=f[cc]=i;
     93         addedge(i,aa);
     94         addedge(i,bb);
     95         addedge(i,cc);
     96     }
     97     for(;i<=3*n+1;i++){
     98         aa=read();
     99         sum[i]=(aa<<1);
    100     }
    101     dfs(1);
    102     q=read();
    103     ans=sum[1]>>1;
    104     for(i=1;i<=q;i++){
    105         aa=read();
    106         sum[aa]^=2;//单点修改
    107         int k=sum[aa]-1; 
    108         aa=f[aa];
    109         access(aa);
    110         splay(aa);//将区间的端点旋转到根 
    111         int p=(~k)?num1[aa]:num2[aa];//找到最深的非1或2点 
    112         if(!p) pusm(aa,k),pushup(aa),ans^=1;//如果这个点不存在,说明就是原树根了 
    113         else{
    114             splay(p);//这个时候aa点已经在p的右子树了 
    115             pusm(c[p][1],k);
    116             pushup(c[p][1]);
    117             sum[p]+=k;
    118             pushup(p);
    119         }
    120         printf("%d\n",ans);
    121     }
    122     return 0;
    123 }

      

    ——抓住了时间,却不会利用的人,终究也逃不过失败的命运。
  • 相关阅读:
    Win7系统安装Centos7.0双系统(一)
    CentOS7安装Oracle 11g R2 详细过程——零基础
    分页整理
    文件压缩与挤压ZIP
    js阻止事件冒泡
    input上传图片
    ios web input 内边阴影
    JS中如何处理多个ajax并发请求?
    jquery的deferred使用详解
    HTTP常见状态码
  • 原文地址:https://www.cnblogs.com/Nelson992770019/p/11333198.html
Copyright © 2011-2022 走看看