• bzoj3223


    Tyvj 1729 文艺平衡树

     HYSBZ - 3223 

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

    Input

    第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数
    接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n 

    Output

    输出一行n个数字,表示原始序列经过m次变换后的结果 

    Sample Input
    5 3
    1 3
    1 3
    1 4

    Sample Output

    4 3 2 1 5

    Hint

    N,M<=100000

    sol:splay区间翻转的板子题,似乎搞了很久qaq

    要支持在平衡树上打标记,下传的时候就是询问的时候下传,比方说查询第K个的数的位置

    翻转的时候打标记就可以了,如果有标记下传的时候交换左右儿子就相当于翻转了(因为是中序遍历)

    Q:交换左右儿子以后不满足左边全部比中间小,右边全部大怎么办?

    A:不用管,因为没有插入操作了,查找第K个只要管好Size就可以了(确切的说不是第K大的数,只是中序遍历第K个)

    Q:怎么找到[l,r]这段区间?

    A:找到 l-1 和 r+1 的位置 ll , rr,把 ll 串到根上,这时所有比在 l-1 之后的都在 ll 的右子树里,再把 rr 串到 ll 上所有比l-1后及比rr+1前的就到rr的左子树里了

    完结撒花!!!


    代码非常丑丑丑丑丑丑丑丑丑丑丑丑丑丑丑

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0'); return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=200005,inf=0x3f3f3f3f;
    int n,m;
    namespace Pht
    {
        int Points=0,Root=0;
        int Child[N][2];
        int Parent[N];
        int Quanzhi[N];
        int Size[N];
        bool Rev[N];
        
        inline void Init();
        inline int Check(int x);
        inline void PushUp(int x);
        inline void PushDown(int x);
        inline void Rotate(int x);
        inline void Splay(int At,int To);
        inline void Insert(int Val);
        inline int Kth(int Id);
        inline void OutPut(int Now);
        inline void Solve();
        
        inline void Init()
        {
            Points=Root=0;
            Insert(-inf);
            Insert(inf);
        }
        inline int Check(int x)
        {
            return (Child[Parent[x]][0]==x)?0:1;
        }
        inline void PushUp(int x)
        {
            Size[x]=Size[Child[x][0]]+Size[Child[x][1]]+1;
        }
        inline void PushDown(int x)
        {
            if((!x)||(!Rev[x])) return;
            swap(Child[x][0],Child[x][1]);
            Rev[x]=0;
            Rev[Child[x][0]]^=1;
            Rev[Child[x][1]]^=1;
        }
        inline void Rotate(int x)
        {
            int y,z,oo;
            y=Parent[x];
            z=Parent[y];
            oo=Check(x);
            Child[y][oo]=Child[x][oo^1]; Parent[Child[x][oo^1]]=y;
            Child[z][Check(y)]=x; Parent[x]=z;
            Child[x][oo^1]=y; Parent[y]=x;
            PushUp(x); PushUp(y);
        }
        inline void Splay(int At,int To)
        {
            while(Parent[At]!=To)
            {
                int Father=Parent[At];
                if(Parent[Father]==To)
                {
                    Rotate(At);
                }
                else if(Check(At)==Check(Father))
                {
                    Rotate(Father); Rotate(At);
                }
                else
                {
                    Rotate(At); Rotate(At);
                }
            }
            if(To==0) Root=At;
        }
        inline void Insert(int Val)
        {
            int Now=Root,Par=0;
            while(Now)
            {
                Par=Now;
                Now=Child[Now][(Val>Quanzhi[Now])?1:0];
            }
            Now=++Points;
            if(Par) Child[Par][(Val>Quanzhi[Par])?1:0]=Now;
            Child[Now][0]=Child[Now][1]=0;
            Parent[Now]=Par;
            Size[Now]=1;
            Quanzhi[Now]=Val;
            Rev[Now]=0;
            Splay(Now,0);
        }
        inline int Kth(int Id)
        {
            int Now=Root;
            for(;;)
            {
                PushDown(Now);
                if(Size[Child[Now][0]]>=Id)
                {
                    Now=Child[Now][0];
                }
                else if(Size[Child[Now][0]]+1==Id)
                {
                    return Now;
                }
                else if(Size[Child[Now][0]]+1<Id)
                {
                    Id-=(Size[Child[Now][0]]+1);
                    Now=Child[Now][1];
                }
            }
        }
        inline void Reverse(int l,int r)
        {
            int ll=Kth(l),rr=Kth(r+2); //找到l-1和r+1的位置
            Splay(ll,0); //所有在l-1之后的都到ll的右子树 
            Splay(rr,ll); //在ll的基础上所有比r+1前的都到rr的左子树,所以[l,r]这段区间就是rr的左子树
            Rev[Child[rr][0]]^=1;
        }
        inline void OutPut(int Now)
        {
            PushDown(Now);
            if(Child[Now][0]) OutPut(Child[Now][0]);
            if(Quanzhi[Now]>=1&&Quanzhi[Now]<=n) W(Quanzhi[Now]);
            if(Child[Now][1]) OutPut(Child[Now][1]);
        }
        inline void Solve()
        {
            int i;
            Init();
            for(i=1;i<=n;i++) Insert(i);
            while(m--)
            {
                int l=read(),r=read();
                Reverse(l,r);
            }
            OutPut(Root);
        }
    }
    int main()
    {
        R(n); R(m);
        Pht::Solve();
        return 0;
    }
    /*
    input
    5 3
    1 3
    1 3
    1 4
    output
    4 3 2 1 5
    */
    View Code

    Ps:我写的似乎是不重的区间翻转,重复的应该也差不多,毕竟只有Insert要用到,大不了一个个插(全是口胡)

  • 相关阅读:
    python中a = a+b与a += b的不同
    python中的全局变量global
    python中星号(*)和双星号(**)的用法
    python循环语句
    python逻辑运算符
    python内置函数 print()
    python 解析迅雷下载链接
    python 正则表达式
    python 读写文件
    python selenium操作cookie
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10667049.html
Copyright © 2020-2023  润新知