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;
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM