codevs3243 区间翻转

题目描述 Description

给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列

输入描述 Input Description

第一行一个数N,下一行N个数表示原始序列,在下一行一个数M表示M次翻转,之后的M行每行两个数L,R表示将区间[L,R]翻转。

输出描述 Output Description

一行N个数 , 表示最终序列。

样例输入 Sample Input

4

1 2 3 4

2

1 2

3 4

样例输出 Sample Output

2 1 4 3

数据范围及提示 Data Size & Hint

对于30%的数据满足n<=100 , m <= 10000

对于100%的数据满足n <= 150000 , m <= 150000

对于100%的数据满足n为2的幂,且L = i * 2^j + 1 , R = (i + 1) * 2^j

正解:splay

解题报告:

  一样的区间翻转,只是我只翻转位置编号,最后对着序列输出就可以了。

  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 = 150011;
 21 int n,m;
 22 int id[MAXN];
 23 int fa[MAXN],c[MAXN][2],size[MAXN];
 24 int tag[MAXN];
 25 int rt;
 26 //splay的有序按照位置有序,结点存储的是值
 27 
 28 inline int getint()
 29 {
 30        int w=0,q=0;
 31        char c=getchar();
 32        while((c<'0' || c>'9') && c!='-') c=getchar();
 33        if (c=='-')  q=1, c=getchar();
 34        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
 35        return q ? -w : w;
 36 }
 37 
 38 inline void update(int now){
 39     int l=c[now][0],r=c[now][1];
 40     size[now]=size[l]+size[r]+1;
 41 }
 42 
 43 inline void pushdown(int now){   
 44     if(tag[now]) {
 45     swap(c[now][0],c[now][1]);//交换,画个图就可以知道
 46     tag[c[now][0]]^=1; tag[c[now][1]]^=1;//标记改变
 47     tag[now]=0;
 48     }
 49 }
 50 
 51 inline void build(int l,int r,int f){
 52     if(l>r) return ;
 53     if(l==r) {
 54     size[l]=1; fa[l]=f;
 55     if(l<f) c[f][0]=l;
 56     else c[f][1]=l;
 57     return ;
 58     }
 59     int mid=(l+r)/2; build(l,mid-1,mid); build(mid+1,r,mid);
 60     fa[mid]=f; if(mid<f) c[f][0]=mid; else c[f][1]=mid;
 61     update(mid);
 62 }
 63 
 64 inline void rotate(int x,int &k){
 65     int y=fa[x],z=fa[y];  int l,r;
 66     if(x==c[y][0]) l=0; else l=1; 
 67     r=l^1;
 68     if(y==k) k=x;
 69     else {
 70     if(c[z][0]==y) c[z][0]=x; 
 71     else c[z][1]=x;
 72     }
 73     fa[x]=z;  fa[y]=x;
 74     fa[c[x][r]]=y; c[y][l]=c[x][r];
 75     c[x][r]=y;
 76     update(y); update(x);//z不需要!!!
 77 }
 78 
 79 inline void splay(int x,int &k){//把x旋到k
 80     int y,z;
 81     while(x!=k) {
 82     y=fa[x]; z=fa[y];
 83     if(y!=k) {
 84         if(c[y][0]==x ^ c[z][0]==y) rotate(x,k);//在不同边时,旋x
 85         else rotate(y,k);//相同边时,旋y
 86     }
 87     rotate(x,k);
 88     }
 89 }
 90 
 91 inline int find(int x,int rank){
 92     pushdown(x);//每次做之前,下传标记
 93     int l=c[x][0],r=c[x][1];
 94     if(size[l]+1==rank) return x;
 95     else if(size[l]>=rank) return find(l,rank);
 96     else return find(r,rank-size[l]-1);//还要减掉根结点那一个点
 97 }
 98 
 99 inline void work(int l,int r){
100     int zuo=find(rt,l),you=find(rt,r+2);//找到与这个区间相邻的两个结点
101     splay(zuo,rt); splay(you,c[rt][1]);//把左相邻结点旋到根,右相邻结点旋到根的右子树,则右相邻结点的左子树即所求区间
102     tag[c[you][0]]^=1;
103 }
104 
105 inline void solve(){
106     n=getint(); 
107     for(int i=1;i<=n;i++) id[i]=getint();
108     build(1,n+2,0);//加两个虚拟结点
109     rt=(n+3)/2;
110 
111     int l,r;
112     m=getint();
113     for(int i=1;i<=m;i++) {
114     l=getint(),r=getint();
115     work(l,r);
116     }
117     for(int i=2;i<=n+1;i++) {
118     printf("%d ",id[find(rt,i)-1]);
119     }
120 }
121 
122 int main()
123 {
124   solve();
125   return 0;
126 }
原文地址:https://www.cnblogs.com/ljh2000-jump/p/5652518.html