首页 > 其他 > 详细

【洛谷P3391】【模板】文艺平衡树

时间:2020-03-15 09:45:35      阅读:80      评论:0      收藏:0      [点我收藏+]

题目

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

思路

Splay 模板。总算是会抠 Splay 了。
Treap 采用键值随机化来维护 BST 平衡,而 Splay 则采用旋转来维护 BST 平衡。基本上每进行一次关于 \(x\) 的操作,就把 \(x\) 旋转至树根。
对于区间旋转的操作,我们以下标建立一棵 Splay,对于旋转 \([l,r]\),我们将 \(l\) 的前驱旋转至树根,\(r\) 的后继旋转至树根的右子节点,那么此时 \(r\) 的后继的左子树即为 \([l,r]\)
那么就把 \(r\) 后继的左子树的树根打上一个懒惰标记,下次旋转该点时就将该点的左右子树互换,类似线段树的标记下传。
时间复杂度不会证。

代码

这份代码还有很多地方可以简化,但是太懒了。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=100010,Inf=2e9;
int n,Q,rt;

struct Splay
{
    int tot,val[N],fa[N],son[N][2],cnt[N],size[N];
    bool tag[N];
    
    void pushup(int x)
    {
        size[x]=size[son[x][1]]+size[son[x][0]]+cnt[x];
    }
    
    void pushdown(int x)
    {
        if (tag[x])
        {
            tag[son[x][0]]^=1; tag[son[x][1]]^=1;
            swap(son[x][0],son[x][1]);
            tag[x]=0;
        }
    }
    
    bool pos(int x)
    {
        return x==son[fa[x]][1];
    }
    
    void build()
    {
        tot=2; rt=1; 
        val[1]=-Inf; val[2]=Inf;
        fa[2]=1; son[1][1]=2;
        cnt[1]=cnt[2]=1;
        pushup(2); pushup(1); 
    }
    
    void rotate(int x)
    {
        pushdown(x);
        int y=fa[x],z=fa[y],k=pos(x),c=son[x][k^1];
        fa[c]=y; son[y][k]=c;
        fa[x]=z; son[z][pos(y)]=x;
        fa[y]=x; son[x][k^1]=y;
        pushup(y); pushup(x);
    }
    
    void splay(int x,int f=0)
    {
        while (fa[x]!=f)
        {
            int y=fa[x],z=fa[y];
            if (z!=f)
            {
                if (pos(x)==pos(y)) rotate(y);
                    else rotate(x);
            }
            rotate(x);
        }
        if (!f) rt=x;
    }
    
    void ins(int x)
    {
        int p=rt,f=0;
        while (p && val[p]!=x)
        {
            f=p;
            if (val[p]<x) p=son[p][1];
                else p=son[p][0];
        }
        if (val[p]==x) cnt[p]++;
        else
        {
            p=++tot;
            val[p]=x; cnt[p]=size[p]=1;
            fa[p]=f; son[f][x>val[f]]=p;
        }
        pushup(p); pushup(f);
        splay(p);
    }
    
    int get_val(int k)
    {
        int p=rt;
        while (1)
        {
            pushdown(p);
            if (size[son[p][0]]>=k) p=son[p][0];
            else if (k<=size[son[p][0]]+cnt[p]) break;
            else k-=size[son[p][0]]+cnt[p],p=son[p][1];
        }
        splay(p);
        return p;
    }
    
    void reverse(int l,int r)
    {
        int p=get_val(l),q=get_val(r+2);
        splay(p); 
        splay(q,p);
        tag[son[q][0]]^=1;
    }
}splay;

void dfs(int x)
{
    if (!x) return;
    splay.pushdown(x);
    dfs(splay.son[x][0]);
    if (x>2) printf("%d ",splay.val[x]);
    dfs(splay.son[x][1]);
}

int main()
{
    scanf("%d%d",&n,&Q);
    splay.build();
    for (int i=1;i<=n;i++)
        splay.ins(i);
    while (Q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        splay.reverse(l,r);
    }
    dfs(rt);
    return 0;
}

【洛谷P3391】【模板】文艺平衡树

原文:https://www.cnblogs.com/stoorz/p/12495375.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!