解题思路
(splay)对于区间的操作,因为(splay)可以任意旋转,比较灵活,所以可以处理区间信息。处理([l,r])时,我们可以把(l-1)这个点转到根,(r+1)这个点转到根的右儿子,那么要处理的区间就是根的右儿子的左子树,然后直接打上标记就行了。然后要插入一个(inf),插入一个(-inf)两个哨兵节点,防止越界。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 100005;
const int inf = 0x3f3f3f3f;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
int n,m;
struct Splay{
int siz[MAXN],ch[MAXN][2],fa[MAXN],val[MAXN],rt,tot,tag[MAXN];
inline bool check(int x){
return (x==ch[fa[x]][1]);
}
inline void pushdown(int x){
tag[ch[x][0]]^=1;tag[ch[x][1]]^=1;tag[x]=0;
swap(ch[x][0],ch[x][1]);
}
int build(int l,int r,int f){
if(l>r) return 0;
int now=++tot,mid=(l+r)>>1;fa[now]=f;
if(mid==1) val[now]=-inf;else if(mid==n+2) val[now]=inf;
else val[now]=mid-1;
ch[now][0]=build(l,mid-1,now);ch[now][1]=build(mid+1,r,now);
siz[now]=siz[ch[now][0]]+siz[ch[now][1]]+1;
return now;
}
int find(int x){
int now=rt;
while(1){
if(tag[now]) pushdown(now);
if(x<=siz[ch[now][0]]) now=ch[now][0];
else {
x-=siz[ch[now][0]]+1;
if(!x) return now;now=ch[now][1];
}
}
}
void rotate(int x){
int y=fa[x],z=fa[y];bool chk=check(x);
ch[y][chk]=ch[x][chk^1];fa[ch[x][chk^1]]=y;
ch[x][chk^1]=y;fa[y]=x;fa[x]=z;if(z) ch[z][(y==ch[z][1])]=x;
siz[y]=siz[ch[y][0]]+siz[ch[y][1]]+1;
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void splay(int x,int y){
if(tag[x]) pushdown(x);
for(int f=fa[x];f!=y;rotate(x),f=fa[x])
if(fa[f]!=y) rotate(check(x)==check(f)?f:x);
if(!y) rt=x;
}
void reverse(int x,int y){
int l=x-1,r=y+1;
l=find(l);r=find(r);
splay(l,0);splay(r,l);
int now=ch[rt][1];now=ch[now][0];
tag[now]^=1;
}
void dfs(int x){
if(tag[x]) pushdown(x);
if(ch[x][0]) dfs(ch[x][0]);
if(val[x]!=inf && val[x]!=-inf)
printf("%d ",val[x]);
if(ch[x][1]) dfs(ch[x][1]);
}
}tree;
int main(){
n=rd(),m=rd();int l,r;
tree.rt=tree.build(1,n+2,0);
while(m--){
l=rd(),r=rd();
tree.reverse(l+1,r+1);
}
tree.dfs(tree.rt);
return 0;
}