JZYZOJ1998 [bzoj3223] 文艺平衡树 splay 平衡树

http://172.20.6.3/Problem_Show.asp?id=1998

平衡树区间翻转的板子,重新写一遍,给自己码一个板子。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<cstdlib>
  7 using namespace std;
  8 const int maxn=100100;
  9 int c[maxn][2],fa[maxn],siz[maxn],rev[maxn];
 10 int n,m,rt;
 11 inline int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 14     while(ch>='0'&&ch<='9'){x*=10;x+=ch-'0';ch=getchar();}
 15     return x*f;
 16 }
 17 inline void pushup(int x){//向上总结siz
 18     siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;
 19 }
 20 inline void pushdown(int x){//向下传递rev标记
 21     if(rev[x]){
 22         swap(c[x][0],c[x][1]);
 23         rev[c[x][0]]^=1;rev[c[x][1]]^=1;
 24         rev[x]=0;
 25     }
 26 }
 27 void build(int l,int r,int pa){//不完全二分建树。。
 28     if(l>r)return;
 29     if(l==r){
 30         fa[l]=pa;siz[l]=1;
 31         if(l<pa)c[pa][0]=l;
 32         else c[pa][1]=l;
 33         return;
 34     }
 35     int mid=(l+r)/2;
 36     build(l,mid-1,mid);build(mid+1,r,mid);
 37     if(mid<pa)c[pa][0]=mid;
 38     else c[pa][1]=mid;
 39     fa[mid]=pa;
 40     pushup(mid);
 41 }
 42 int find(int x,int rank){//二分查找排名为rank的数
 43     //因为建树的时候已经默认查找的数在数组中的序号就是它本身
 44     //操作不会改变一个节点的序号,只会改变点和点的联系,从而改变排列顺序
 45     pushdown(x);
 46     //find中的pushdown相当于为后面的splay“开路”
 47     int l=c[x][0],r=c[x][1];
 48     if(siz[l]+1==rank)return x;
 49     else if(siz[l]>=rank)return find(l,rank);
 50     else return find(r,rank-siz[l]-1);
 51 }
 52 void rotate(int x,int &k){//向上旋转
 53     int pa=fa[x];int gpa=fa[pa],l,r;
 54     if(c[pa][0]==x) l=0;
 55     else l=1; r=l^1;//上旋前x在pa的l方向
 56     if(pa==k) k=x;
 57     else{
 58         //如果x旋转不到k,需要关注上旋后和gpa的儿子关系
 59         //观察后面的调用,旋转到k时gpa的儿子关系相当于直接被继承,
 60         if(c[gpa][0]==pa)c[gpa][0]=x;
 61         else c[gpa][1]=x;
 62     }
 63     fa[x]=gpa;fa[pa]=x;fa[c[x][r]]=pa;
 64     c[pa][l]=c[x][r];c[x][r]=pa;
 65     pushup(x);pushup(pa);
 66     
 67 }
 68 void splay(int x,int &k){
 69     while(x!=k){
 70         int pa=fa[x];int gpa=fa[pa];
 71         if(pa!=k){//这里的异或处理了顺位和逆位两种情况
 72             /*顺位先将pa上旋至k,逆位直接将x向上旋,
 73             避免树失衡。*/
 74             if((c[pa][0]==x)^(c[gpa][0]==pa))rotate(x,k);
 75             else rotate(pa,k);
 76         }rotate(x,k);
 77     }
 78 }
 79 void rever(int l,int r){
 80     int x=find(rt,l),y=find(rt,r+2);//找到两个数的位置
 81     splay(x,rt);splay(y,c[x][1]);//将两个数调为根和其rc
 82     //此时,两个数之间的数都在根的rc的lc上
 83     /*    我们开始开始的建树从1到n+2就是为了将1和n+2作为边界
 84     事实上进行操作的是2到n+1这n个数。我们最后取的时候要减1。
 85     所以,翻转l+1到r+1即可。
 86     */
 87     rev[c[y][0]]^=1;
 88 }
 89 int main(){
 90     n=read();m=read();
 91     int x,y;
 92     build(1,n+2,0);rt=(n+3)/2;
 93     for(int i=1;i<=m;i++){
 94         x=read();y=read();
 95         rever(x,y);
 96     }
 97     for(int i=2;i<=n+1;i++){
 98         printf("%d ",find(rt,i)-1);
 99     }
100     return 0;
101 }
View Code

 

posted @ 2018-01-25 09:50  鲸头鹳  阅读(105)  评论(0编辑  收藏  举报