Splay区间翻转

如题
其实就是用Splay来维护一个序列,而不再是一棵二叉查找树了
然后建立两个虚点1和n+2每次操作时将[l,r]变成[l+1,r+1]
翻转就是将Rank为l的点splay到根,将Rank为r+2的点splay到根的右儿子,然后给r+2的左儿子(此时就是要修改的区间)打上rev标记。
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N=1e5+5;
int n,m,sz,root;
int key[N],ch[N][2],rev[N],f[N],size[N];
inline bool get(int x){return ch[f[x]][1]==x;}
inline void update(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1;}
inline void clear(int x){key[x]=ch[x][0]=ch[x][1]=rev[x]=f[x]=size[x]=0;}
inline void rotate(int x){
    int y=f[x],z=f[y],w=get(x),w2=get(y);
    ch[y][w]=ch[x][w^1];f[ch[y][w]]=y;
    ch[x][w^1]=y;f[y]=x;
    f[x]=z;if(z)ch[z][w2]=x;
    update(y);update(x);
}
inline void splay(int x,int goal){
    for(int fa=0;(fa=f[x])!=goal;rotate(x))
        if(f[fa]!=goal)
            rotate((get(x)==get(fa)?fa:x));
    if(!goal)root=x;
}
inline void pushdown(int x){
    if(rev[x]){
        if(ch[x][0])rev[ch[x][0]]^=1;
        if(ch[x][1])rev[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);rev[x]=0;
    }
}
inline void insert(int x){
    if(!root){key[++sz]=x;size[sz]=1;root=sz;return;}
    int now=root,fa=0;
    while(1){
        pushdown(now);
        fa=now;
        now=ch[now][x>key[now]];
        if(!now){
            ch[fa][x>key[fa]]=++sz;
            key[sz]=x;size[sz]=1;f[sz]=fa;
            splay(sz,0);return;
        }
    }
}
inline int kth(int k){
    int now=root;
    while(1){
        pushdown(now);
        if(ch[now][0]&&k<=size[ch[now][0]])now=ch[now][0];
        else{
            if(k<=size[ch[now][0]]+1){splay(now,0);return now;}
            k-=size[ch[now][0]]+1;now=ch[now][1];
        }
    }
}
inline void print(int x){
    pushdown(x);
    if(ch[x][0])print(ch[x][0]);
    if(key[x]>1&&key[x]<n+2)printf("%d ",key[x]-1);
    if(ch[x][1])print(ch[x][1]);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n+2;i++)insert(i);
    while(m--){
        int l=read(),r=read();
        l=kth(l);r=kth(r+2);splay(l,0);splay(r,l);
        rev[ch[r][0]]^=1;
    }
    kth(2);
    print(root);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值