hdu1890 splay维护区间翻转

这题的建模有点不太一样,是按结点横坐标赋予键值的

同时每次rotate和splay时都要注意下往上往下更新

/*
先建立好splay tree,将结点按num/输入顺序排序,遍历时每次将当前结点提到根节点,输出其在splay树中排第几个
然后rev左子树,最后remove
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#include<algorithm>
#define maxn 100005
struct A{
    int num,id;
    bool operator < (const A &a) const {
        if(num==a.num) return id<a.id;
        return num<a.num;
    }
}a[maxn];
int pre[maxn],ch[maxn][2],size[maxn],keys[maxn],tot,root,n;
int rev[maxn];
inline void pushup(int r){
    size[r]=size[ch[r][0]]+size[ch[r][1]]+1;
}
void update(int r){//就是交换r的两个子区间
    if(!r) return;
    else {
        swap(ch[r][0],ch[r][1]);
        rev[r]^=1;
    }       
}      
inline void pushdown(int r){
    if(rev[r]){//把左右子树rev
        update(ch[r][0]);
        update(ch[r][1]);
        rev[r]=0;
    }
}
inline void newnode(int &r,int fa,int key){
    r=key;
    pre[r]=fa;
    ch[r][0]=ch[r][1]=0;
    size[r]=0;
    keys[r]=key;
    rev[r]=0;
}
void build(int &r,int L,int R,int fa){
    if(L>R) return;
    int m=L+R>>1;
    newnode(r,fa,m);
    build(ch[r][0],L,m-1,r);
    build(ch[r][1],m+1,R,r);
    pushup(r);
}
void init(){
    root=tot=0;
    ch[root][0]=ch[root][1]=0;
    size[root]=0;
    rev[root]=0;
    build(root,1,n,0);
}           
//rotate操作只会改变r,fa,ch[r][kind]三个结点
void rotate(int x,int kind){
    int fa=pre[x];
    pushdown(fa);
    pushdown(x);
    ch[fa][!kind]=ch[x][kind];
    pre[ch[x][kind]]=fa;
    if(pre[fa])
        ch[pre[fa]][ch[pre[fa]][1]==fa]=x;
    pre[x]=pre[fa];
    pre[fa]=x;
    ch[x][kind]=fa;
    pushup(fa);
    pushup(x);
}           
void splay(int r,int goal){
    pushdown(r);
    while(pre[r]!=goal){
        if(pre[pre[r]]==goal){
            pushdown(pre[r]);
            pushdown(r);
            rotate(r,ch[pre[r]][0]==r);
        }
        else {
            pushdown(pre[pre[r]]);
            pushdown(pre[r]);
            pushdown(r);
            int fa=pre[r];
            int kind=(ch[pre[fa]][0]==fa);
            if(ch[fa][kind]==r){//方向相反
                rotate(r,!kind);
                rotate(r,kind);
            }
            else {
                rotate(fa,kind);
                rotate(r,kind);
            }
        }
    }
    if(goal==0) root=r;
    pushup(r);
}     
void remove(){//删掉根节点
    if(ch[root][0]==0){
        root=ch[root][1];
        pre[root]=0;
    }
    else {
        pushdown(root);
        int tmp=ch[root][0];
        while(ch[tmp][1])
            pushdown(tmp),tmp=ch[tmp][1];
        splay(tmp,root);
        ch[tmp][1]=ch[root][1];
        pre[ch[root][1]]=tmp;
        root=tmp;
        pre[root]=0;
        pushup(root);
    }
}
  



int main(){
    while(scanf("%d",&n) && n){
        init();
            for(int i=1;i<=n;i++)
            scanf("%d",&a[i].num),a[i].id=i;
        sort(a+1,a+1+n);
        for(int i=1;i<n;i++){
            splay(a[i].id,0);//按权值大小遍历点
            update(ch[root][0]);//逆转区间
            printf("%d ",i+size[ch[root][0]]);//输出结点在当前伸展树中排的序号
            remove(); 
        }
          printf("%d\n",n);
    }
    return 0;
}

 

posted on 2018-11-21 22:10  zsben  阅读(191)  评论(0编辑  收藏  举报

导航