hdu 1890 伸展树区间翻转

 

吐槽一下,还是太弱了,这个被认为伸展树水题的题本菜搞了好久。。。

给你n个数

每次将第i个位置到第i大的数所在位置 之间的数进行翻转,输出的是第i大的数所在的位置

伸展树的节点不需要记录任何东西,直接按照各个数在数组中的顺序建树即可(即建好伸展树后中序遍历的结果就是原数组的数)

所以伸展树的节点编号的相对大小代表的是这个数在数组中的下标,这点一定要搞清楚

然后建树的时候顺便记录下第i大的数所在的节点编号是什么。

最后每次将第i大的数旋转到根,然后 左子树的大小 就是在数组中相对位置在这个数的左边的数的个数  因为每次将第i大的数翻转到第i个位置时,这个数就不会用到了,

所以每次统计好后就直接把根节点给删了(删除也有点小技巧,详见代码),这样的话答案就是 i+size[ch[root][0]] 了

由于并没有提取区间的操作,所以我没有另外加两个节点,所以我在n==1的时候需要特判一下

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define Keytree (ch[ ch[root][1] ][0])
const int maxn = 100010;
struct node {
    int num,id;
}in[maxn];
int id[maxn];
int cmp(node a,node b){
    if(a.num!=b.num) return a.num<b.num;
    return a.id<b.id;
}
struct SplayTree{
    int tot,root;
    int pre[maxn];
    int size[maxn];
    int ch[maxn][2];
    inline void Rotate(int x, int c) {    // 旋转, c=0 左旋, c=1 右旋
        int y = pre[x];
        pushdown(y);
        pushdown(x);
        ch[y][!c] = ch[x][c];
        if ( ch[x][c] )    pre[ ch[x][c] ] = y;
        pre[x] = pre[y];
        if ( pre[y] )    ch[ pre[y] ][ ch[pre[y]][1] == y ] = x;
        ch[x][c] = y;
        pre[y] = x;
        pushup(y);
    }
    inline void Splay(int x, int f) {    // 把结点x转到结点f的下面
        pushdown(x);
        while ( pre[x] != f ) {
            int y = pre[x], z = pre[y];
            pushdown(z);    pushdown(y);    pushdown(x);    // 旋转前必须先去除反转标记
            if ( pre[ pre[x] ] == f ) {
                Rotate(x, ch[pre[x]][0] == x);
            }
            else {
                if ( ch[z][0] == y ) {
                    if ( ch[y][0] == x ) 
                        Rotate(y, 1), Rotate(x, 1);
                    else 
                        Rotate(x, 0), Rotate(x, 1);
                }
                else {
                    if ( ch[y][0] == x ) 
                        Rotate(x, 1), Rotate(x, 0);
                    else 
                        Rotate(y, 0), Rotate(x, 0);
                }
            }
        }
        pushup(x);
        if ( f == 0 )    root = x;
    }
    inline void Select(int k, int f) {    // 把第k个点旋转到f的下面
        int x = root;
        while ( 1 ) {
            pushdown(x);
            if ( k == size[ ch[x][0] ] + 1 ) 
                break;
            if ( k <= size[ ch[x][0] ] )
                x = ch[x][0];
            else {
                k -= (size[ ch[x][0] ] + 1);
                x = ch[x][1];
            }
        } 
        Splay(x, f);
    }
    inline void del_root(){//删除根节点
        int t=root;
        if(ch[root][1]) {
            root=ch[root][1];
            Select(1,0);//把右子树中序遍历的第一个点旋转到根(因为这个点的左儿子肯定为空)
            ch[root][0]=ch[t][0];//将原先根节点的左子树接到当前根节点的左子树上
            if(ch[t][0]) pre[ch[t][0]]=root;
        }
        else 
            root=ch[root][0];

        pre[root]=0;
        pushup(root);
    }
    inline void pushup(int x){
        size[x]=size[ ch[x][0] ] + size[ ch[x][1] ] +1;
    }
    inline void pushdown(int x){
        if(flip[x]){
            flip[x]=0;
            flip[ch[x][0]]^=1;
            flip[ch[x][1]]^=1;
            swap(ch[x][0],ch[x][1]);
        }
    }
    void Newnode(int &x,int f){
        x=++tot;
        pre[x]=f;
        ch[x][0]=ch[x][1]=0;
        flip[x]=0;
        size[x]=1;
    }
    void build(int &x,int l,int r,int f){
        if(l>r) return ;
        int mid=(l+r)>>1;
        Newnode(x,f);
        map[id[mid]]=x;
        build(ch[x][0],l,mid-1,x);
        build(ch[x][1],mid+1,r,x);
        pushup(x);
    }
    void init(int n){
        int i;
        pre[0]=ch[0][0]=ch[0][1]=0;
        size[0]=flip[0]=tot=0;
        for(i=1;i<=n;i++) {
            scanf("%d",&in[i].num);
            in[i].id=i;
        }
        sort(in+1,in+n+1,cmp);
        for(i=1;i<=n;i++) id[in[i].id]=i;
        map[id[1]] = 1;
        map[id[n]] = 2;
        Newnode(root,0);
        Newnode(ch[root][1],root);
        build(Keytree,2,n-1,ch[root][1]);
        pushup(ch[root][1]);
        pushup(root);
    }
    void solve(int n){
        for(int i=1;i<=n;i++){
            Splay(map[i],0);
            printf("%d",i+size[ch[root][0]]);
            if(i<n) printf(" ");
            flip[ch[root][0]]^=1;
            del_root();
        }
        puts("");
    }
    int map[maxn];
    int flip[maxn];
}spt;
int main(){
    int n;
    while(scanf("%d",&n),n)    {
        if(n==1) {scanf("%*d");printf("1\n");continue;}
        spt.init(n);
        spt.solve(n);
    }
    return 0;
}

 

 

posted @ 2012-06-25 10:35  Because Of You  Views(2757)  Comments(2Edit  收藏  举报