题目链接:戳这里
转自:戳这里
关于splay入门:戳这里
题意:给n个数,进行m次操作,每次都从n个数中取出连续的数放在最前面。
解题思路:splay的区间操作。
附代码:
1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 int n,m,sz,rt; 5 int fa[100005],c[100005][2],id[100005]; 6 int size[100005]; 7 bool rev[100005]; 8 void pushup(int k) 9 { 10 int l=c[k][0],r=c[k][1]; 11 size[k]=size[l]+size[r]+1; 12 } 13 void pushdown(int k) 14 { 15 int l=c[k][0],r=c[k][1]; 16 if(rev[k]) 17 { 18 swap(c[k][0],c[k][1]); 19 rev[l]^=1;rev[r]^=1; 20 rev[k]=0; 21 } 22 } 23 void rotate(int x,int &k) 24 { 25 int y=fa[x],z=fa[y],l,r; 26 if(c[y][0]==x)l=0;else l=1;r=l^1; 27 if(y==k)k=x; 28 else {if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;} 29 fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 30 c[y][l]=c[x][r];c[x][r]=y; 31 pushup(y);pushup(x); 32 } 33 void splay(int x,int &k) 34 { 35 while(x!=k) 36 { 37 int y=fa[x],z=fa[y]; 38 if(y!=k) 39 { 40 if(c[y][0]==x^c[z][0]==y)rotate(x,k); 41 else rotate(y,k); 42 } 43 rotate(x,k); 44 } 45 } 46 int find(int k,int rank) 47 { 48 pushdown(k); 49 int l=c[k][0],r=c[k][1]; 50 if(size[l]+1==rank)return k; 51 else if(size[l]>=rank)return find(l,rank); 52 else return find(r,rank-size[l]-1); 53 } 54 void rever(int l,int r) 55 { 56 int x=find(rt,l),y=find(rt,r+2); 57 splay(x,rt);splay(y,c[x][1]); 58 int z=c[y][0]; 59 rev[z]^=1; 60 } 61 void build(int l,int r,int f) 62 { 63 if(l>r)return; 64 int now=id[l],last=id[f]; 65 if(l==r) 66 { 67 fa[now]=last;size[now]=1; 68 if(l<f)c[last][0]=now; 69 else c[last][1]=now; 70 return; 71 } 72 int mid=(l+r)>>1;now=id[mid]; 73 build(l,mid-1,mid);build(mid+1,r,mid); 74 fa[now]=last;pushup(mid); 75 if(mid<f)c[last][0]=now; 76 else c[last][1]=now; 77 } 78 int main() 79 { 80 scanf("%d%d",&n,&m); 81 for(int i=1;i<=n+2;i++) 82 id[i]=++sz; 83 build(1,n+2,0);rt=(n+3)>>1; 84 for(int i=1;i<=m;i++) 85 { 86 int l,r; 87 scanf("%d%d",&l,&r); 88 rever(1,l+r-1); //区间通过3次翻转,达到洗牌效果 89 rever(1,r); 90 rever(r+1,l+r-1); 91 } 92 for(int i=2;i<=n+1;i++) 93 printf("%d ",find(rt,i)-1); 94 return 0; 95 }