维护序列。
需要兹瓷区间翻转。
嘿嘿嘿裸题。
注意遍历treap的时候也要down标记啊!
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10;
int left[maxn],right[maxn],key[maxn],fix[maxn],size[maxn],sta[maxn];
bool rev[maxn];
int i,j,k,l,r,mid,t,n,m,top,root,cnt;
int rand() {
static int rand_seed=1542071823;
rand_seed+=rand_seed<<1|1;
return rand_seed;
}
void update(int x){
size[x]=size[left[x]]+size[right[x]]+1;
}
void solve(int x){
if (!x) return;
solve(left[x]);
solve(right[x]);
update(x);
}
void mark(int x){
rev[x]^=1;
}
void down(int x){
if (rev[x]){
if (left[x]) mark(left[x]);
if (right[x]) mark(right[x]);
swap(left[x],right[x]);
rev[x]=0;
}
}
void split(int x,int y,int &l,int &r){
if (!x){
l=r=0;
return;
}
down(x);
if (size[left[x]]+1<=y){
split(right[x],y-size[left[x]]-1,l,r);
right[x]=l;
update(x);
l=x;
}
else{
split(left[x],y,l,r);
left[x]=r;
update(x);
r=x;
}
}
void merge(int l,int r,int &x){
if (!l||!r){
x=l+r;
return;
}
down(l);
down(r);
if (fix[l]<fix[r]){
merge(right[l],r,right[l]);
x=l;
}
else{
merge(l,left[r],left[r]);
x=r;
}
update(x);
}
void travel(int x){
if (!x) return;
down(x);
travel(left[x]);
cnt++;
printf("%d",key[x]);
if (cnt<n) printf(" ");
travel(right[x]);
}
int main(){
//freopen("3223.in","r",stdin);freopen("3223.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n){
key[i]=i;
fix[i]=rand();
j=0;
while (top&&fix[i]<fix[sta[top]]){
right[sta[top]]=j;
j=sta[top];
left[i]=sta[top];
top--;
}
if (top) right[sta[top]]=i;
sta[++top]=i;
}
root=sta[1];
solve(root);
while (m--){
scanf("%d%d",&j,&k);
split(root,k,l,r);
split(l,j-1,l,mid);
mark(mid);
merge(l,mid,l);
merge(l,r,root);
}
cnt=0;
travel(root);
}