如题
其实就是用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;
}