• BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊


    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2002

    [分析]

      看完LCT的理论分析,找入门题熟悉一下代码的时候...就看了这题

      思路感觉比较明确:因为跳跃就是连边的感觉,而且每个点的出度都等于1,这不就是一棵树吗(当然所有能弹飞的都连到根上)

      

      当然这种树的形态会改变,正好符合动态树的处理范畴.询问的是需要几次弹出去,也就是深度比它浅的有多少,这个也可以用splay做.

      但是我抄的是kuangbin的模板.感觉很诡异...因为给你的树的father和平衡树里用的father是一样的....惊恐!旋转splay的时候是可以改变father的值的,也就是每次翻转都会让这棵树的形态变化!

      然而还是可以A,不得不服....

      这便需要反思了...因为每次询问都会打通任督二脉(雾)是Access这个节点[这里利用了根节点的father为0来打通],那么不管你之前怎么改变了树的形态,这个节点最后还是找到了自己到根节点的这条链[虽然现在可能不再是一条链,但会在一颗二叉平衡树里],旋转之后得到的答案也是正确的.而删除某条边的时候,也是先将这个边的发出点Access,也就处理了它后面节点的后顾之忧[断开了],再Splay就让它在树根的位置而且注定没有右子树[之前被断开了],让左子树成为新的平衡树树根就好[前面的节点也没有变化],而添加的时候也只是连虚边,这样操作就是没有问题的.在操作中树的形态不是很重要,但是整个的到根的一条链能通过Access找到,这个很重要.

    代码[%kuangbin]:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    inline int in(){
        int x=0,f=1;char ch=getchar();
        while((ch>'9' || ch<'0') && ch!='-') ch=getchar();
        if(ch=='-') ch=getchar(),f=-1;
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    const int maxn=200010;
    
    struct Node{
        int l,r,f,sz;
        bool rt;
    }s[maxn];
    
    int n,m;
    
    void update(int x){
        s[x].sz=s[s[x].l].sz+s[s[x].r].sz+1;
    }
    
    void zig(int x){
        int y=s[x].f;
        s[x].f=s[y].f;
        if(s[y].rt) s[x].rt=true,s[y].rt=false;
        else{
            if(s[s[y].f].l==y) s[s[y].f].l=x;
            else s[s[y].f].r=x;
        }
        s[y].l=s[x].r;
        if(s[x].r) s[s[x].r].f=y;
        s[y].f=x,s[x].r=y;
        update(y),update(x);
    }
    
    void zag(int x){
        int y=s[x].f;
        s[x].f=s[y].f;
        if(s[y].rt) s[x].rt=true,s[y].rt=false;
        else{
            if(s[s[y].f].l==y) s[s[y].f].l=x;
            else s[s[y].f].r=x;
        }
        s[y].r=s[x].l;
        if(s[x].l) s[s[x].l].f=y;
        s[y].f=x,s[x].l=y;
        update(y),update(x);
    }
    
    void Splay(int x){
        int y;
        while(!s[x].rt){
            y=s[x].f;
            if(s[y].rt){ if(s[y].l==x) zig(x);
                else zag(x);}
            else{
                int z=s[y].f;
                if(y==s[z].l){ if(x==s[y].l) zig(y),zig(x);
                    else zag(x),zig(x);}
                else{ if(x==s[y].r) zag(y),zag(x);
                    else zig(x),zag(x);}
            }
        }
    }
    
    /*
        Access(x)表示的是将x与根节点相连的过程
        s[i].r[平衡树中的右节点] 在实际树中的意义是接在i后的点
        last表示的是现在x所在的链需要与之前x所在的链相连,也就需要将原本连接的部分舍去
        last初始为0,可以让x一开始便与后面的链断开
        所以操作就是一步步地往上爬,每次将上次的位置和这次的连上,直到根的过程
    */
    
    void Access(int x){
        int last=0;
        for(;x;x=s[last=x].f){
            Splay(x);
            s[s[x].r].rt=true;
            s[x].r=last;
            s[last].rt=false;
            update(x);
        }
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("2002.in","r",stdin);
        freopen("2002.out","w",stdout);
    #endif
        
        int t,ord,x,d;
        
        n=in();
        for(int i=1;i<=n;i++){
            t=in()+i;
            s[i].f=min(t,n+1);
            s[i].rt=true;
            s[i].sz=1;
        }
        s[0].rt=s[n+1].rt=true,s[n+1].sz=1;
        m=in();
        while(m--){
            ord=in();
            if(ord==1){
                x=in()+1;
                Access(x),Splay(x);
                printf("%d
    ",s[s[x].l].sz);
            }
            else{
                x=in()+1;d=in();
                Access(x),Splay(x);
                s[s[x].l].f=s[x].f;
                s[s[x].l].rt=true;
                s[x].l=0,s[x].f=0;
                update(x);
                s[x].f=min(n+1,x+d);
            }
        }
    
        return 0;
    }
    View Code

      后来与同学讨论了一下...对这种记录方法有所改观.

      father其实有两种含义,当rt=true的时候,这个点事实上记录的是这条链的path_father这也就证明了之前Access的复杂度(每次splay之后都是直接跳链)

      当rt=false的时候,father就是单纯的splay中的用法了,用来进行zig,zag,splay操作.

    好神啊!

  • 相关阅读:
    不测的秘密:精准测试之路----读书笔记(第二章)
    如何使用for循环连续的实例化多个对象!
    java如何在一个有序的数组类插入一个数!
    webstrom 常用快捷键
    如何使Label带有链接??此法感觉有点取巧!!!
    System.DateTime的一些格式
    如何解决”无法将类型为“System.DateTime”的对象强制转换为类型“System.String”。“
    如何解决“连接未关闭。 连接的当前状态为打开”问题
    c语言中 %p的含义
    什么情况下用递归?
  • 原文地址:https://www.cnblogs.com/Robert-Yuan/p/5125445.html
Copyright © 2020-2023  润新知