「模板」 FHQ_Treap 区间翻转

Posted Capella

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「模板」 FHQ_Treap 区间翻转相关的知识,希望对你有一定的参考价值。

「模板」 FHQ_Treap 区间翻转

<题目链接>


没有旋转的 Treap 实现区间操作的功能,很好理解,也很好写,只是速度不算太快。

对于要翻转的区间,把整棵 Treap(存有区间 \([1,n]\) 的信息)Split 成 \([1,l-1]\)\([l,r]\)\([r+1,n]\) 三部分,给中间部分的根节点打上标记,再一边下传标记一边 Merge 回来。

注意 Split 时,要按元素个数,不能按权值,因为元素个数可以通过维护节点信息的 size 域而直接得到,但随着区间的翻转,权值会乱套。

一定注意先推标记!!先推标记!!先推标记!!

就因为标记推晚了,我调了一天。

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
using std::swap;
const int MAXN=100010;
int n,m;
class FHQ_Treap
{
    public:
        FHQ_Treap(void)
        {
            rt=cnt=0;
            memset(a,0,sizeof a);
        }
        void Insert(int x)
        {
            s[++cnt]=node(x,Random(),1);
            Merge(rt,rt,cnt);
        }
        void Reverse(int x,int y)
        {
            int l=0,r=0,t=0;
            Split(rt,x-1,l,t),Split(t,y-x+1,t,r);
            s[t].lazy^=1,Merge(l,l,t),Merge(rt,l,r);
        }
        void Print(void)
        {
            DFS(rt),putchar(\n);
        }
    private:
        bool a[MAXN];
        int rt,cnt;
        struct node
        {
            int v,p,size,lazy,c[2];
            node(int _v=0,int _p=0,int _size=0)
            {
                v=_v,p=_p,size=_size,lazy=0;
                memset(c,0,sizeof c);
            }
        }s[MAXN];
        int Random(void)
        {
            int x;
            while(a[x=rand()%MAXN]);
            a[x]=1;
            return x;
        }
        void Update(int i)
        {
            s[i].size=s[s[i].c[0]].size+s[s[i].c[1]].size+1;
        }
        void PushDown(int i)
        {
            int &l=s[i].c[0],&r=s[i].c[1];
            swap(l,r);
            if(l)
                s[l].lazy^=1;
            if(r)
                s[r].lazy^=1;
            s[i].lazy=0;
        }
        void Split(int i,int x,int &l,int &r)
        {
            if(!i)
            {
                l=r=0;
                return;
            }
            if(s[i].lazy)
                PushDown(i);
            int t=s[s[i].c[0]].size+1;
            if(x<t)
                Split(s[r=i].c[0],x,l,s[i].c[0]);
            else
                Split(s[l=i].c[1],x-t,s[i].c[1],r);
            Update(i);
        }
        void Merge(int &i,int l,int r)
        {
            if(!l || !r)
            {
                i=l|r;
                return;
            }
            if(s[l].p>s[r].p)
            {
                if(s[l].lazy)
                    PushDown(l);
                Merge(s[i=l].c[1],s[l].c[1],r);
            }
            else
            {
                if(s[r].lazy)
                    PushDown(r);
                Merge(s[i=r].c[0],l,s[r].c[0]);
            }
            Update(i);
        }
        void DFS(int i)
        {
            if(s[i].lazy)
                PushDown(i);
            if(s[i].c[0])
                DFS(s[i].c[0]);
            printf("%d ",s[i].v);
            if(s[i].c[1])
                DFS(s[i].c[1]);
        }
}T;
int main(int argc,char *argv[])
{
    srand((unsigned)time(NULL));
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i)
        T.Insert(i);
    for(int i=1,l,r;i<=m;++i)
    {
        scanf("%d %d",&l,&r);
        T.Reverse(l,r);
    }
    T.Print();
    return 0;
}

谢谢阅读。

以上是关于「模板」 FHQ_Treap 区间翻转的主要内容,如果未能解决你的问题,请参考以下文章

片段(Java) | 机试题+算法思路+考点+代码解析 2023

洛谷 3391 模板文艺平衡树 Treap区间翻转

Splay(区间翻转) 模板

华为OD机试真题Python实现翻转单词顺序真题+解题思路+代码(2022&2023)

模板文艺平衡树(Splay)

P3391 模板文艺平衡树(Splay)