hdu 1890 splay

题意:给定数列,要求每次找到最小的数,输出是第几个,将其本身连同左边翻转,然后删除这个数。如果最小的数不止一个,则取元数列中靠前的那个。

分析:要注意边界情况,以及孩子为0的情况 。结点存储原数列中的下标,子树中最小元素的下标。为了找到最小元素,还要存储最小元素来自左子树还是右子树。

 

 

#define keyTree (ch[ ch[root][1] ][0])
const int vaf=0x3fffffff;
const int MaxN = 100005;
struct SplayTree{
    int sz[MaxN];
    int ch[MaxN][2];//ch[][0]左孩子  ch[][1]右孩子
    int pre[MaxN];//父结点
    int root,top1,top2;
    int sta[MaxN],que[MaxN];

    inline void Rotate(int x,int f) {//f==0左旋转  f==1右旋转
        int y=pre[x];
        PushDown(y); PushDown(x);
        ch[y][!f]=ch[x][f]; pre[ch[x][f]]=y;
        pre[x]=pre[y];
        if(pre[x]) ch[pre[y]][ch[pre[y]][1]==y]=x;
        ch[x][f]=y; pre[y]=x;
        PushUp(y);
        //if(y==root)root=x;
    }
    inline void Splay(int x,int goal) {//将x旋转到goal的下面
        PushDown(x);
        while(pre[x]!=goal) {
            if(pre[pre[x]]==goal) Rotate(x,ch[pre[x]][0]==x);
            else{
                int y=pre[x],z=pre[y],f=(ch[z][0]==y);
                if(ch[y][f]==x) Rotate(x,!f),Rotate(x,f);
                else Rotate(y,f),Rotate(x,f);
            }
        }
        PushUp(x);
        if(goal==0) root=x;
    }
    inline void RotateTo(int k,int goal) {//将第k个数旋转到goal下面
        int x=root;
        PushDown(x);
        k++; //由于加入了两个边界结点  所以应为k+1位
        while(sz[ch[x][0]]!=k-1) {
            if(k-1<sz[ch[x][0]]) x=ch[x][0];
            else k-=(sz[ch[x][0]]+1),x=ch[x][1];
            PushDown(x);
        }
        Splay(x,goal);
    }
    inline void Delete(int x) {//把以x为祖先结点删掉放进内存池,回收内存
        int fa=pre[x],head=0,tail=0;
        for(que[tail++]=x;head<tail;head++){
            sta[top2++]=que[head];
            if(ch[que[head]][0]) que[tail++]=ch[que[head]][0];
            if(ch[que[head]][1]) que[tail++]=ch[que[head]][1];
        }
        ch[fa][ch[fa][1]==x]=0;
        while(fa!=root) PushUp(fa),fa=pre[fa];
        PushUp(root);
    }
    inline int pred(int x){//在x的子树中找x的前驱
        int y=ch[x][0];
        PushDown(x); PushDown(y);
        while(ch[y][1]) y=ch[y][1],PushDown(y);
        //if(y==0) y=1;                 //x是其子树中最前面的,没有前驱
        return y;
    }
    inline int succ(int x){//在x的子树中找x的后继
        int y=ch[x][1];
        PushDown(x); PushDown(y);
        while(ch[y][0]) y=ch[y][0],PushDown(y);
        //if(y==0) y=2;                 //x是其子树中最后面的,没有后继
        return y;
    }
    //以上一般不修改//////////////////////////////////////////////////

    inline void NewNode(int &x,int c) {
        x=++top1;
        ch[x][0]=ch[x][1]=pre[x]=0;
        sz[x]=1;

        p[x]=pos[x]=c;    //
        rev[x]=0;
        dir[x]=0;
    }
    inline void makeTree(int &x,int l,int r,int father){
        if(l>r) return;
        int m=(l+r)>>1;
        NewNode(x,m);    //num[m]权值改成题目所需的
        makeTree(ch[x][0],l,m-1,x);
        makeTree(ch[x][1],m+1,r,x);
        pre[x]=father;
        PushUp(x);
    }
    inline void init(int n) {
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        root=top1=top2=0;
        dir[0]=0;
        p[0]=pos[0]=0;
        rev[0]=0;
        num[0]=vaf;
        //为了方便处理边界,加两个边界顶点
        NewNode(root,0);   //
        NewNode(ch[root][1],0);    //
        pre[top1]=root;
        sz[root]=2;

        makeTree(keyTree,1,n,ch[root][1]);
        PushUp(ch[root][1]);
        PushUp(root);
    }


    inline void PushDown(int x) {
        if(rev[x]){
            if(ch[x][0]) rev[ch[x][0]]^=1;
            if(ch[x][1]) rev[ch[x][1]]^=1;
            rev[x]=0;
            swap(ch[x][0],ch[x][1]);
            dir[x]*=-1;
        }
    }

    inline void PushUp(int x) {
        sz[x]=1+sz[ch[x][0]]+sz[ch[x][1]];//sz[0]==0

        pos[x]=p[x],dir[x]=0;
        int pl=pos[ch[x][0]],pr=pos[ch[x][1]];
        if(num[pl]<num[pos[x]]||(num[pl]==num[pos[x]]&&pl<pos[x]))
            pos[x]=pl,dir[x]=-1;
        if(num[pr]<num[pos[x]]||(num[pr]==num[pos[x]]&&pr<pos[x]))
            pos[x]=pr,dir[x]=1;
    }

    inline void UpDate(int m){
        Splay(1,0);
        int p0=root,p1,p2;
        while(dir[p0]){
            PushDown(p0);
            if(dir[p0]==-1)p0=ch[p0][0];
            else p0=ch[p0][1];
        }
        Splay(p0,root);
        p1=succ(p0);
        Splay(p1,root);
        printf("%d",sz[keyTree]+m);
        rev[p0]=true;
        Splay(p0,0);
        p1=pred(p0); p2=succ(p0);
        Splay(p1,0);
        Splay(p2,root);
        Delete(p0);
    }

    int num[MaxN];//只在建树时使用
    int p[MaxN];
    int pos[MaxN];
    int dir[MaxN];
    int rev[MaxN];
}spt;


int main() {
    int n ;
    while(cin>>n,n){
        for(int i=1;i<=n;i++) scanf("%d",&spt.num[i]);
        spt.init(n);
        for(int m=0;m<n;m++){
            spt.UpDate(m);
            if(m<n-1)printf(" ");
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2013-06-22 16:22  心向往之  阅读(297)  评论(0编辑  收藏  举报