• 「清华集训 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;
    }
    
  • 相关阅读:
    函数重载和函数指针在一起
    Uva
    Uva
    Uva
    Uva
    Uva
    CCPC-Wannafly-day5
    CCPC-Wannafly-day3
    CCPC-Wannafly-day2
    CCPC-Wannafly-Winter 2020.01.12总结
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/13096133.html
Copyright © 2020-2023  润新知