给定一个区间和m次操作,每次操作将一段区间翻转,求m次操作后的区间。
链接
题解
Splay复习题
用Splay维护[0,n+2]。假如操作是翻转[a,b],将a-1转至根,b+1转至右子树,则b+1的左子树即为要维护的区间,用翻转标记处理即可。
代码
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 200010
using namespace std;
int n,m,i,x,y,a,b,root;
int f[N],s[N][2],size[N],tag[N];
inline void Swap(int &x,int &y){x^=y^=x^=y;}
inline int Get(int x){return (x==s[f[x]][1]);}
inline void Push(int x){
Swap(s[x][0],s[x][1]);
tag[s[x][0]]^=1; tag[s[x][1]]^=1;
tag[x]=0;
}
inline void Update(int x){
size[x]=size[s[x][0]]+size[s[x][1]]+1;
}
inline int Build(int l,int r){
int mid=(l+r)>>1;
if (l>r) return 0;
s[mid][0]=Build(l,mid-1);
s[mid][1]=Build(mid+1,r);
Update(mid);
f[s[mid][0]]=f[s[mid][1]]=mid;
return mid;
}
inline void Rotate(int x){
int fa=f[x],gf=f[fa],o=Get(x),oo=Get(fa);
f[x]=gf; f[fa]=x; f[s[x][o^1]]=fa;
s[fa][o]=s[x][o^1]; s[x][o^1]=fa; s[gf][oo]=x;
Update(fa); Update(x);
}
inline void Splay(int x,int y){
for (;f[x]!=y;Rotate(x))
if (f[f[x]]!=y) Rotate((Get(x)==Get(f[x]))?f[x]:x);
if (!y) root=x;
}
inline int Find(int x){
int i=root;
while (1){
if (tag[i]) Push(i);
if (x==size[s[i][0]]+1) return i;
else if (x<=size[s[i][0]]) i=s[i][0];
else x-=(size[s[i][0]]+1),i=s[i][1];
}
}
inline void Print(int x){
if (!x) return;
if (tag[x]) Push(x);
Print(s[x][0]);
if (x!=1&&x!=n+2) printf("%d ",x-1);
Print(s[x][1]);
}
int main(){
scanf("%d%d",&n,&m);
root=Build(1,n+2);
while (m--){
scanf("%d%d",&x,&y);
a=Find(x); b=Find(y+2);
Splay(a,0); Splay(b,a);
tag[s[s[a][1]][0]]^=1;
}
Print(root);
return 0;
}
声明:
本文采用
BY-NC-SA
协议进行授权,如无注明均为原创,转载请注明转自
Marvolo
本文地址: [LOJ105] 文艺平衡数
本文地址: [LOJ105] 文艺平衡数