「清华集训 2017」小 Y 和二叉树

传送门

首先,我们贪心地选一个点来作为中序遍历的第一个点,也就是说这个点不可能有左子树。

显然符合条件的点的度数小于 \(3\)

然后我们就考虑从所选的这个点 \(dfs\),捋清最后的二叉树中节点之间的父子关系。

考虑 \(dfs\) 的过程(记当前点为 \(u\)):

如果 \(u\) 是由它左下方的点向上走得到的,并且 \(u\) 还连出去两个点 \(x, y\),那么我们就要考虑把哪个点作为 \(u\) 的右儿子,哪个点作为 \(u\) 的父亲。

我们还是贪心地想,显然我们要把编号越小越好的点在中序遍历中放在 \(u\) 的右边的位置,如果我们用 \(mn_i\) 表示连向 \(i\) 的联通块中,可以作为这一段在中序遍历中的第一个的编号最小的点,那么我们肯定要选择 \(x, y\)\(mn\) 值较小的点来作为 \(u\) 的右儿子,另一个作为父亲,因为右儿子是会先排入中序遍历当中的。

类似地,如果只连出去唯一的一个 \(x\),我们就把 \(mn_x\)\(u\) 本身的编号作比较,考虑把 \(x\) 作为父亲还是右儿子。

如果没有点了的话,当前的 \(u\) 显然就会作为二叉树最后的根。

有了以上的思路,对于 \(u\) 从它上方的点连下来的情况也就不难讨论了。

最后再跑一遍中序遍历输出方案就好了。

参考代码:

#include <cstring>
#include <cstdio>
#include <cmath>

int min(int a, int b) { return a < b ? a : b; }

void swap(int& a, int& b) { int t = a; a = b; b = t; }

template < class T > void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while ('0' > c || c > '9') f |= c == '-', c = getchar();
    while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
    s = f ? -s : s;
}

const int _ = 1e6 + 5;

int n, dgr[_], G[_][3], ch[2][_], st, root, mn[_];

void dfs_mn(int u, int f) {
    for (int i = 0; i < 3; ++i) {
        int v = G[u][i]; if (!v || v == f) continue ;
        dfs_mn(v, u), mn[u] = min(mn[u], mn[v]);
    }
}

void dfs(int u, int f, int opt) {
    int x = 0, y = 0;
    for (int i = 0; i < 3; ++i)
        if (G[u][i] && G[u][i] != f) {
            if (!x) x = G[u][i]; else if (!y) y = G[u][i];
        }
    if (opt == 0) {
        ch[0][u] = f;
        if (x && y) {
            if (mn[x] > mn[y]) swap(x, y); dfs(x, u, 1), dfs(y, u, 0);
        }
        else if (x + y) { x = x + y;
            if (mn[x] < x) root = u, dfs(x, u, 1); else dfs(x, u, 0);
        } else root = u;
    } else {
        if (opt == 1) ch[1][f] = u;
        if (opt == 2) ch[0][f] = u;
        if (x && y) {
            if (mn[x] > mn[y]) swap(x, y); dfs(x, u, 2), dfs(y, u, 1);
        } else if (x + y) { x = x + y;
            if (mn[x] > u) dfs(x, u, 1); else dfs(x, u, 2);
        }
    }
}

void Dfs(int x) { if (x) Dfs(ch[0][x]), printf("%d ", x), Dfs(ch[1][x]); }

int main() {
#ifndef ONLINE_JUDGE
    freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout);
#endif
    read(n);
    memset(mn, 0x3f, sizeof mn);
    for (int i = 1; i <= n; ++i) {
        read(dgr[i]);
        for (int j = 0; j < dgr[i]; ++j) read(G[i][j]);
        if (dgr[i] <= 2) { mn[i] = i; if (!st) st = i; }
    }
    dfs_mn(st, 0), dfs(st, 0, 0), Dfs(root);
    return 0;
}
posted @ 2020-06-11 21:15  Sangber  阅读(233)  评论(0编辑  收藏  举报