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







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