BZOJ3223 Tyvj 1729 文艺平衡树

 

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

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 }

 

posted @ 2016-07-08 10:14  ljh_2000  阅读(161)  评论(0编辑  收藏  举报