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

题目背景

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

题目描述

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

输入输出格式

输入格式:

 

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

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

 

输出格式:

 

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

输入输出样例

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


splay模板题,维护该序列的中序遍历不变,然后每次通过旋转节点使操作的区间变作一颗字树,然后打上标记即可。
什么是splay?
一棵伸展树......
什么是伸展树?
最近刚学,我个人的理解,大概就是一个能在不破坏二叉搜索树结构(即中序遍历始终为升序)的情况下
通过旋转一个节点到他根节点位置使得操作区间恰好全部位于一棵子树内的方法。


然后就打上标记,之后在类似线段树一样的pushdown传递信息就好了。

代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define mod
#define mid (R+L>>1)
#define M 2000010
using namespace std;
LL read(){
    LL nm=0,oe=1;char cw=getchar();
    while(!isdigit(cw)) oe=cw=='-'?-oe:oe,cw=getchar();
    while(isdigit(cw)) nm=nm*10+(cw-'0'),cw=getchar();
    return nm*oe;
}
LL n,m,l[M],r[M],tp[M],ad,sz[M],tg[M],ace,a,b,p,q,cnt;
bool flag=false;
void pushdown(LL x){
    if(tg[x]==0) return;
    tg[x]=0,swap(l[x],r[x]);
    tg[l[x]]^=1,tg[r[x]]^=1;
}
void pushup(LL x){sz[x]=sz[l[x]]+sz[r[x]]+1;}
LL build(LL L,LL R,LL rt){
    if(L>R) return 0;
    tp[mid]=rt,sz[mid]=1;
    if(L==R) return L;
    l[mid]=build(L,mid-1,mid);
    r[mid]=build(mid+1,R,mid);
    sz[mid]+=sz[l[mid]]+sz[r[mid]];
    return mid;
}
void rotate(LL x){
    if(ace==x) return;
    LL top=tp[x];
    pushdown(top),pushdown(x);
    if(top==ace) ace=x,tp[x]=n+1,tp[top]=x;
    else{
        if(l[tp[top]]==top) l[tp[top]]=x;
        else r[tp[top]]=x;
        tp[x]=tp[top],tp[top]=x;
    }
    if(l[top]==x) l[top]=r[x],tp[r[x]]=top,r[x]=top;
    else r[top]=l[x],tp[l[x]]=top,l[x]=top;
    pushup(top),pushup(x);
}
void oper(LL x){
    if(x==ace||tp[x]==ace){return;}
    LL top=tp[x];
    pushdown(top);
    if(tp[top]==ace) rotate(x);
    else if(l[l[tp[top]]]==x||r[r[tp[top]]]==x) rotate(top);
    else rotate(x);
}
LL find(LL x,LL pos){
    pushdown(x);
    if(sz[l[x]]==pos-1) return x;
    if(sz[l[x]]<pos-1) return find(r[x],pos-sz[l[x]]-1);
    else return find(l[x],pos);
}
void ans(LL x){
    if(x==0) return;
    pushdown(x);
    ans(l[x]);
    if(x<n&&x>1){
        if(flag) printf(" ");
        flag=true;
        printf("%lld",x-1);
    }
    ans(r[x]);
}
int main(){
    n=read()+2,m=read(),ace=build(1,n,n+1);
    while(m--){
        a=read(),b=read();
        p=find(ace,a),q=find(ace,b+2);
        while(tp[q]!=ace&&q!=ace) oper(q);
        if(q!=ace) rotate(q);
        while(tp[p]!=ace) oper(p);
        tg[r[p]]^=1;
    }
    ans(ace);
    return 0;
}

我这里还是写的比较模糊,我也是通过了解别人的博客才理解了splay

就是这个 -> http://blog.csdn.net/skydec/article/details/20151805

原文地址:https://www.cnblogs.com/OYJason/p/7887057.html