P3391 【模板】文艺平衡树(Splay)

题目背景

这是一道经典的Splay模板题——文艺平衡树。

题目描述

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

输入输出格式

输入格式:

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2,n-1,n)m表示翻转操作次数

接下来m行每行两个数[l,r]数据保证1≤l≤r≤n 1

输出格式:

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

输入输出样例

输入样例#1: 
5 3
1 3
1 3
1 4
输出样例#1: 
4 3 2 1 5

说明

n,m≤100000

代码

l-1r+1分别旋转到根节点和根节点右儿子处,
那么r+1的左子树即是区间[l,r]
在其根处打上标记然后在查询k大和输出中序遍历时下传标记即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+100;
int ch[maxn][2],size[maxn],cnt[maxn],val[maxn],fa[maxn],rev[maxn];
int root,ncnt;
int n,m;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
inline void swap(int& x,int&y)
{
    x^=y,y^=x,x^=y;
}
inline void pushup(int u)
{
    size[u]=size[ch[u][0]]+size[ch[u][1]]+cnt[u];
}
inline void pushdown(int u)
{
    if(rev[u])
    {
        rev[ch[u][0]]^=1;
        rev[ch[u][1]]^=1;
        swap(ch[u][0],ch[u][1]);
        rev[u]^=1;
    }
}
inline int chk(int u)
{
    return ch[fa[u]][1]==u;
}
void rotate(int u)
{
    int f=fa[u],ff=fa[f],k=chk(u),s=ch[u][k^1];
    ch[f][k]=s,fa[s]=f;
    ch[ff][chk(f)]=u,fa[u]=ff;
    ch[u][k^1]=f,fa[f]=u;
    pushup(u),pushup(f);
}
void splay(int u,int goal=0)
{
    while(fa[u]!=goal)
    {
        int f=fa[u],ff=fa[f];
        if(ff!=goal)
        {
            if(chk(u)==chk(f))rotate(f);
            else rotate(u);
        }
        rotate(u);
    }
    if(!goal)root=u;
}
void insert(int x)
{
    int u=root,f=0;
    while(u&&val[u]!=x)
    f=u,u=ch[u][x>val[u]];
    if(u)cnt[u]++;
    else 
    {
        u=++ncnt;
        if(f)ch[f][x>val[f]]=u;
        fa[u]=f,val[u]=x;
        cnt[u]=size[u]=1;
        ch[u][0]=ch[u][1]=0;
    }
    splay(u);
}
int kth(int k)
{
    int u=root;
    while(1)
    {
        pushdown(u);
        if(ch[u][0]&&k<=size[ch[u][0]])
        u=ch[u][0];
        else if(k>size[ch[u][0]]+cnt[u])
        k-=size[ch[u][0]]+cnt[u],u=ch[u][1];
        else return u;
    }
}
void reverse(int l,int r)
{
    int x=kth(l),y=kth(r+2);
    splay(x),splay(y,x);
    rev[ch[y][0]]^=1;
}
void output(int u)
{
    pushdown(u);
    if(ch[u][0])output(ch[u][0]);
    if(val[u]&&val[u]<=n)printf("%d ",val[u]);
    if(ch[u][1])output(ch[u][1]);
}
int main()
{
    n=read(),m=read();
    for(int i=0;i<=n+1;i++)insert(i);
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        reverse(x,y);
    }
    output(root);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/DriverBen/p/10884580.html