题目链接:https://www.luogu.org/problem/P3391
从题解里学到了直接建树,就不需要一个个insert了。
假设我们要翻转区间[L,R],可以先把L-1对应的结点转到根root,R+1对应的结点转到根的右节点right,此时right的左子树就是在[L,R]范围内的结点啦。此时把这个子树每个结点的左右儿子都翻一下,整个区间就翻过来了呢。
然鹅没有必要全部翻过来,打个标记就好了,后面每次用到的时候都pushdown下去。
需要注意的是,因为翻转[1,n]的时候,木有0和n+1,所以建树前加了个-inf和inf。
#include<bits/stdc++.h>
#define lchild(x) (T[x].ch[0])
#define rchild(x) (T[x].ch[1])
#define fa(x) (T[x].fa)
#define root (T[0].ch[1])
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int cnt;
ll ans=1e18;
int tag[maxn];
struct node{
int val,ch[2],num,sz,fa;//value,孩子,该value的个数,子树中所有value的num和,父亲
}T[maxn];
inline int newnode(int u,int fa,int num){//增加一个value为u,父亲为fa的结点,个数记为num个
T[++cnt].fa=fa;T[cnt].val=u;
T[cnt].sz=1;T[cnt].num=num;
lchild(cnt)=rchild(cnt)=0;//***初始化
return cnt;
}
bool ident(int x){return lchild(fa(x))==x?0:1;}
void link(int x,int fa,int dir){T[fa(x)=fa].ch[dir]=x;}
void update(int x){
T[x].sz=T[lchild(x)].sz+T[rchild(x)].sz+T[x].num;}
inline void pushdown(int x){
if(x&&tag[x]){
tag[lchild(x)]^=1;
tag[rchild(x)]^=1;
tag[x]=0;
swap(lchild(x),rchild(x));
}
}
void rotate(int x){
int dir=ident(x),Y=fa(x),Z=fa(Y);
link(T[x].ch[dir^1],Y,dir);
link(x,Z,ident(Y));
link(Y,x,dir^1);
update(Y);update(x);//此处要先更新Y再更新x,因为此时Y是x的孩子
}
void splay(int x,int to){//x==to也可以处理
to=fa(to);
while(fa(x)!=to){
if(fa(fa(x))==to)rotate(x);
else if(ident(x)==ident(fa(x))) rotate(fa(x)),rotate(x);
else rotate(x),rotate(x);
}
}
int get(int now,int dir){//now是点的编号,dir==0找前驱,dir==1找后继,此处是要找的now已经是根的情况下
now=T[now].ch[dir];
pushdown(now);
if(!now) return -1;
while(T[now].ch[dir^1]) now=T[now].ch[dir^1],pushdown(now);
return T[now].val;
}
int find(int x){//找到value为x的编号
int now=root;
while(1){
pushdown(now);
if(T[now].val==x){ splay(now,root);return now;}
int dir=x<T[now].val?0:1;
if(!T[now].ch[dir]) return 0;
now=T[now].ch[dir];
}
}
void dele(int x){//删掉value为x的点
x=find(x);//注释掉这句就是删除编号为x的点啦
if(!x) return;
//if(T[x].num>1){T[x].num--;T[x].sum--;return ;}//决定是删掉该权值的一个点还是删掉权值的所有点
if(lchild(x)){
int pre=lchild(x);
pushdown(pre);
while(rchild(pre)) pre=rchild(pre),pushdown(pre);
splay(pre,lchild(root));
link(rchild(root),pre,1);
link(pre,0,1);
update(pre);
}else{
root=rchild(x);
T[root].fa=0;
}
}
int kth(int k){//value第k大的点(value)的编号,不去重的哦,去重的话sz对每种value只记1即可
int now=root;
while(1){
pushdown(now);
int used=T[now].sz-T[rchild(now)].sz;
if(T[lchild(now)].sz<k&&k<=used){ splay(now,root);return now;}
if(k<used) now=lchild(now);
else now=rchild(now),k-=used;
}
}
int n,m;
int a[maxn];
int build(int fa,int l,int r){
if(l>r){return 0;}
int m=l+r>>1;
int now=newnode(a[m],fa,1);
lchild(now)=build(now,l,m-1);
rchild(now)=build(now,m+1,r);
update(now);
return now;
}
void rev(int l,int r){
l=kth(l),r=kth(r);
splay(l,root);
splay(r,rchild(root));
tag[lchild(rchild(root))]^=1;
}
void dfs(int t){
// printf(" t=%d\n",t);
pushdown(t);
if(lchild(t)) dfs(lchild(t));
if(T[t].val!=1e9&&T[t].val!=-1e9)printf("%d ",T[t].val);
if(rchild(t)) dfs(rchild(t));
}
int main(){
scanf("%d%d",&n,&m);
a[1]=-1e9;a[n+2]=1e9;
for(int i=2;i<=n+1;i++) a[i]=i-1;
root=1;
build(0,1,n+2);
//dfs(root);
while(m--){
int l,r;
scanf("%d%d",&l,&r);
rev(l,r+2);
}
dfs(root);
return 0;
}