• BZOJ_3223: Tyvj 1729 文艺平衡树 _splay


    题意: 

    您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

    分析:

    splay维护区间操作的模板题。

    节点维护区间信息。

    提取区间:把l-1旋到根,再把r+1旋到根的右儿子,那么根的右儿子的左子树则是我们需要的区间。

    建树:递归建树,左儿子还是右儿子取决于在当前区间的位置。

    区间反转:打标记的思想,每个标记只对儿子生效。

    其他:建两个哨兵节点来保护1和n

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 100050
    int ch[N][2],f[N],siz[N],val[N];
    int rt,sz,n,m,tag[N];
    void clear(int x){ ch[x][0]=ch[x][1]=f[x]=siz[x]=val[x]=0; }
    int get(int x){ return ch[f[x]][1]==x; }
    void up(int x){ if(x)siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
    void pud(int x){ if(!tag[x])return ;tag[x]=0;swap(ch[x][0],ch[x][1]);tag[ch[x][0]]^=1;tag[ch[x][1]]^=1; }
    void rotate(int x)
    {
        int y=f[x],z=f[y],k=get(x);
        ch[y][k]=ch[x][k^1];f[ch[y][k]]=y;ch[x][k^1]=y;f[y]=x;f[x]=z;
        if(z) ch[z][ch[z][1]==y]=x; up(y),up(x);
        if(rt==y)rt=x;
    }
    void splay(int x,int y)
    {
        for(int fa;(fa=f[x])!=y;rotate(x))
            if(f[fa]!=y)
                rotate((get(x)==get(fa)) ? fa : x);
    }
    int find(int x)
    {
        int now=rt;
        while(1)
        {
            pud(now);
            if(x<=siz[ch[now][0]])now=ch[now][0];
            else
            {
                x-=siz[ch[now][0]]+1;
                if(!x)return now;
                now=ch[now][1];
            }
        }
    }
    void build(int fa,int l,int r)
    {
        if(l>r)return ;
        int mid = l + r >> 1;
        ch[fa][mid > fa] = mid;
        siz[mid] = 1;
        val[mid] = mid - 1;
        f[mid] = fa;
        build(mid, l, mid - 1);
        build(mid, mid + 1, r);
        up(mid);
    }
    void reverse(int x,int y)
    {
        x=find(x);
        y=find(y);
        splay(x,f[rt]);
        splay(y,rt);    
        tag[ch[y][0]]^=1;
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        int i,x,y;
        build(0,1,n+2);
        rt=n+3>>1;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            reverse(x,y+2);
        }
        for(i=2;i<=n;i++) printf("%d ",val[find(i)]);
        printf("%d",val[find(n+1)]);
    }
    
  • 相关阅读:
    如何获取QQ的clientkey
    自动输入QQ密码
    Ext Tree 操作类
    QQ消息记录文件压缩方法
    见过最恶心的代码,发泄一下。。。
    今天尝试获取QQ的clientkey未果,做个记号
    用c# 调用并调试c++的代码
    托盘管理 隐藏/显示/单击/右键/双击/改变位置
    在XP下是可以查看进程命令行参数的
    充分利用你的“二脑”
  • 原文地址:https://www.cnblogs.com/suika/p/8592872.html
Copyright © 2020-2023  润新知