• SGU 187 Twist and whirl


      伸展树。。。

      赤果果地抄袭雷哥的代码:http://www.cnblogs.com/jianglangcaijin/archive/2013/01/21/2869148.html

      题意:输入n,m。给你n个数,初始排列是1到n,然后有m个操作,每次操作给两个数L,R,把(L,R)区间上的数的顺序颠倒,输出最终的顺序。

      伸展树就是二叉查找排序数,一个节点的左子树上的数都比它小,右子树上的数比它大。这道题要在首尾加上哨兵,即有n+2个数,操作(L,R),就是把L-1旋转至根节点,然后把R+1旋转至L-1的右子树,那么R+1的左子树就是区间(L,R),然后把这个区间颠倒。

      因为是第一次看伸展树的代码,雷哥定义的数组看了好大一会儿才知道干吗用的。

      c[f][0]是节点f的左子树,c[f][1]就是节点f的右子树。p[x]是节点x的父节点,s[x]是以节点x为跟的数的节点数,sign[x]表示节点x是否颠倒,和线段树有点像。

    下面就贴代码了,函数的功能也在代码里注释。

    #include<cstdio>
    #include<string>
    #include<algorithm>
    using namespace std;
    
    const int N=130005;
    int n,m;
    int root;
    int sign[N],c[N][2],s[N],p[N];
    void down(int x)          //将以节点x为根的树颠倒
    {
        if(!sign[x])    return ;
        sign[x]=0;
        swap(c[x][0],c[x][1]);
        sign[c[x][0]]^=1;
        sign[c[x][1]]^=1;
    }
    void update(int f,int x,int flag)//建立节点x,使它的父节点为f,flag表示它是左子树还是右子树
    {
        p[x]=f;
        if(!f)  return ;
        c[f][flag]=x;
        s[f]=1+s[c[f][0]]+s[c[f][1]];
    }
    int build(int L,int R)       //建树
    {
        if(L>R) return 0;
        int m=(L+R)>>1;
        update(m,build(L,m-1),0);
        update(m,build(m+1,R),1);
        return m;
    }
    void rotate(int x)         //旋转节点x
    {
        int P=p[x],G=p[P];
        if(c[P][0]==x)//如果x是P的左子树
        {
            update(P,c[x][1],0);//x的右子树转为P的左子树
            update(x,P,1);//P成为x的右子树
            update(G,x,!(c[G][0]==P));
        }
        else
        {
            update(P,c[x][0],1);
            update(x,P,0);
            update(G,x,!(c[G][0]==P));
        }
    }
    void splay(int x,int &goal)
    {
        int P=p[x],G=p[P],limit=p[goal];
        while(P!=limit)
        {
            if(G!=limit && (c[G][0]==P)==(c[P][0]==x))  rotate(P);
            rotate(x);
            P=p[x];
            G=p[P];
        }
        goal=x;
        down(goal);
    }
    int select(int x)
    {
        int t=root;
        while(1)
        {
            down(t);
            if(s[c[t][0]]+1==x)    break;
            if(s[c[t][0]]+1>x)     t=c[t][0];
            else            x-=s[c[t][0]]+1,t=c[t][1];
        }
        return t;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        root=build(1,n+2);
        int l,r;
        while(m--)
        {
            scanf("%d%d",&l,&r);
            int r1=select(l);
            int r2=select(r+2);
            splay(r1,root);
            splay(r2,c[r1][1]);
            int x=c[root][1];
            x=c[x][0];
            sign[x]^=1;
        }
        for(int i=2;i<=n+1;i++)  printf("%d ",select(i)-1);
        puts("");
        return 0;
    }
  • 相关阅读:
    写写我的这几天,损失惨重
    ArcIMS9.0安装指南图解
    《亲爱的界面,让用户乐于使用、爱不释手》小编推介
    从图灵原创谈起,带你走进国产技术书的时代
    【民间图灵奖】读《图灵的秘密》写读后感获图灵水杯
    2012年的这些经典书目你读了没?
    2012年图灵技术图书大盘点
    就让推荐,系统实践起来吧!
    用编程工具实现数据可视化的几个选择
    你未必知道的CSS故事:揭开leading的面纱
  • 原文地址:https://www.cnblogs.com/yongren1zu/p/3286192.html
Copyright © 2020-2023  润新知