Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
Input
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n
Output
输出一行n个数字,表示原始序列经过m次变换后的结果
Sample Input
5 3
1 3
1 3
1 4
1 3
1 3
1 4
Sample Output
4 3 2 1 5
HINT
N,M<=100000
Source
正解:splay
解题报告:
像我这种蒟蒻,居然还不会splay区间翻转。我真弱真的。
以前懒得学splay是因为每次都有set,偷懒。。。但是碰到这种题目也是gg,所以不得不学一学。
看了hzwer的代码,还是全都弄懂了。不具体说了,很简单的、、、
代码如下:
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 100011; 21 int n,m; 22 int fa[MAXN],c[MAXN][2],size[MAXN]; 23 int tag[MAXN]; 24 int rt; 25 //splay的有序按照位置有序,结点存储的是值 26 27 inline int getint() 28 { 29 int w=0,q=0; 30 char c=getchar(); 31 while((c<'0' || c>'9') && c!='-') c=getchar(); 32 if (c=='-') q=1, c=getchar(); 33 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 34 return q ? -w : w; 35 } 36 37 inline void update(int now){ 38 int l=c[now][0],r=c[now][1]; 39 size[now]=size[l]+size[r]+1; 40 } 41 42 inline void pushdown(int now){ 43 if(tag[now]) { 44 swap(c[now][0],c[now][1]);//交换,画个图就可以知道 45 tag[c[now][0]]^=1; tag[c[now][1]]^=1;//标记改变 46 tag[now]=0; 47 } 48 } 49 50 inline void build(int l,int r,int f){ 51 if(l>r) return ; 52 if(l==r) { 53 size[l]=1; fa[l]=f; 54 if(l<f) c[f][0]=l; 55 else c[f][1]=l; 56 return ; 57 } 58 int mid=(l+r)/2; build(l,mid-1,mid); build(mid+1,r,mid); 59 fa[mid]=f; if(mid<f) c[f][0]=mid; else c[f][1]=mid; 60 update(mid); 61 } 62 63 inline void rotate(int x,int &k){ 64 int y=fa[x],z=fa[y]; int l,r; 65 if(x==c[y][0]) l=0; else l=1; 66 r=l^1; 67 if(y==k) k=x; 68 else { 69 if(c[z][0]==y) c[z][0]=x; 70 else c[z][1]=x; 71 } 72 fa[x]=z; fa[y]=x; 73 fa[c[x][r]]=y; c[y][l]=c[x][r]; 74 c[x][r]=y; 75 update(y); update(x);//z不需要!!! 76 } 77 78 inline void splay(int x,int &k){//把x旋到k 79 int y,z; 80 while(x!=k) { 81 y=fa[x]; z=fa[y]; 82 if(y!=k) { 83 if(c[y][0]==x ^ c[z][0]==y) rotate(x,k);//在不同边时,旋x 84 else rotate(y,k);//相同边时,旋y 85 } 86 rotate(x,k); 87 } 88 } 89 90 inline int find(int x,int rank){ 91 pushdown(x);//每次做之前,下传标记 92 int l=c[x][0],r=c[x][1]; 93 if(size[l]+1==rank) return x; 94 else if(size[l]>=rank) return find(l,rank); 95 else return find(r,rank-size[l]-1);//还要减掉根结点那一个点 96 } 97 98 inline void work(int l,int r){ 99 int zuo=find(rt,l),you=find(rt,r+2);//找到与这个区间相邻的两个结点 100 splay(zuo,rt); splay(you,c[rt][1]);//把左相邻结点旋到根,右相邻结点旋到根的右子树,则右相邻结点的左子树即所求区间 101 tag[c[you][0]]^=1; 102 } 103 104 inline void solve(){ 105 n=getint(); m=getint(); 106 build(1,n+2,0);//加两个虚拟结点 107 rt=(n+3)/2; 108 109 int l,r; 110 for(int i=1;i<=m;i++) { 111 l=getint(),r=getint(); 112 work(l,r); 113 } 114 for(int i=2;i<=n+1;i++) { 115 printf("%d ",find(rt,i)-1); 116 } 117 } 118 119 int main() 120 { 121 solve(); 122 return 0; 123 }