#bzoj3393#二叉樹(Splay / RMQ)

3393: 二叉樹

時間限制: 1 Sec  內存限制: 512 MB

題目描述

 給定一棵二叉樹,節點標號從1到n。在不改變其中序遍歷的情況下,請改變樹的結構,使得這棵二叉樹的先序遍歷(前序遍歷)字典序最小。

輸入

第一行一個整數n,表示二叉樹的節點數。
接下來n行,每行兩個整數。第i行的兩個整數表示編號爲i的節點的左兒子和右兒子的編號(不存在即爲0)。

輸出

輸出一行n個整數,表示不改變中序遍歷的情況下字典序最小的前序遍歷序列。

樣例輸入

5
5 4
0 0
2 1
0 0
0 0

樣例輸出

1 2 3 5 4

提示

1     3        N/A

2     4        N/A

3    10        N/A

4    100       樹爲一條鏈,且只存在右兒子關係。

5    1000      給出的樹滿足排序二叉樹的性質。即任意一個節點

6    100000    左子樹中所有值<該節點<右子樹中所有值。

7    65535     滿二叉樹

8    100000    N/A

9    100000    N/A




這題是學長的t2,當時看了樣例,感覺想到了平衡樹中的旋轉操作zig,zag,就沒再往其它方面想,也沒再想由中序遍歷和任一遍歷可確定一棵二叉樹這回事了。

考試時這麼做:

首先把1轉到root(虛擬根)兒子去,然後從小到大循環,將i和父親比較,如果父親大於i就rotato向上旋轉,直到條件不滿足。

考試後正解這麼做:

因爲已知中序遍歷,那麼可以根據中序來構造一個先序遍歷,一定能確定一棵二叉樹。

所以每次找區間中最小數輸出,然後左邊,然後右邊,遞歸深度爲log級別。


Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int Maxn = 100000;

int N, Root;
bool tg;
int fa[Maxn + 5], ch[Maxn + 5][2];

bool getint(int & num){
    char c; int flg = 1;    num = 0;
    while((c = getchar()) < '0' || c > '9'){
        if(c == '-')    flg = -1;
        if(c == -1) return 0;
    }
    while(c >= '0' && c <= '9'){
        num = num * 10 + c - 48;
        if((c = getchar()) == -1)   return 0;
    }
    num *= flg;
    return 1;
}

void Rotato(int x){
    if(! x || fa[x] == 0)  return ;
    int y = fa[x], z = fa[y];
    bool flg = (ch[y][1] == x);
    ch[y][flg] = ch[x][! flg];
    if(ch[x][! flg])    fa[ch[x][! flg]] = y;
    ch[x][! flg] = y;
    fa[y] = x;
    fa[x] = z;
    if(z)   ch[z][ch[z][1] == y] = x;
}

void Splay(int x, int goal){
    for(int y; (y = fa[x]) != goal; Rotato(x)){
        int z;
        if((z = fa[y]) != goal){
            if((ch[z][1] == y) == (ch[y][1] == x))
                Rotato(y);
            else Rotato(x);
        }
    }
    if(goal == 0)   Root = x;
}

void Print(int r){
    if(tg) putchar(32);
    printf("%d", r);
    tg = 1;
    if(ch[r][0])
        Print(ch[r][0]);
    if(ch[r][1])
        Print(ch[r][1]);
}

int main(){
    //freopen("bitree.in", "r", stdin);
    //freopen("bitree.out", "w", stdout);
    getint(N);
    for(int i = 1; i <= N; ++ i)
        getint(ch[i][0]), getint(ch[i][1]),
        fa[ch[i][0]] = fa[ch[i][1]] = i;
    fa[0] = 0;
    for(int i = 1; i <= N; ++ i)    if(! fa[i]){
        Root = i;
        break;
    }
    ch[0][1] = Root;
    if(Root != 1)
        Splay(1, 0);
    for(int i = 2; i <= N; ++ i)
        while(fa[i] > i)
            Rotato(i);
    Print(Root);
    return 0;
}







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章