其他分享
首页 > 其他分享> > CSP-S 2019 树上的数

CSP-S 2019 树上的数

作者:互联网

树上的数

题面
现在有一棵树,每个点上有一个点权,你切断一条边,就会交换边上两个点的点权,求\(1~N\)点权的最小字典序。

\(\text{subtask1}\) \(N \leq 10\)

考场上暴力标配,\(\Theta(N!)\)枚举所有删边顺序,然后取字典序最小的一组。

\(\text{subtask2}\) 存在度数为\(N - 1\)的节点

存在度数为\(N-1\)的节点,那么这个图一定是菊花图。
我们设菊花图入度为\(N-1\)的点为\(rt\)。
我们每次删边一段必定是\(rt\),假设我们删边顺序是\(p\),\(p_i\)表示第\(i\)次删的点编号。
第\(i\)次删的边就是\(rt -> p_i\)。
每次删边,当前\(p_i\)的点权就确定了,这个性质比较好。
经过几遍模拟,我们发现\(a_{p_1}\)到了\(p_2\),\(a_{p_2}\)到了\(p_3\),\(a_{p_{n-1}}\)到了\(rt\)。
这样我们是不是形成了一个环的形式。
\(rt->p_1->p_2->p_3...->p_{n-1}->rt\)
要想让字典序最小,我们贪心的选择能得到的最小的数字,并且这个环要不能是多个小环。
我们如果想让数字\(j\)到\(i\)点的话,那么首先\(j\)这个数字没有用过,并且\(j\)和\(p_i\)不在同一个环里(不然形成不了一个大环)。
时间复杂度\(O(N^2)\)

namespace subtask2 {
    int fa[N], ans[N];
    bool vis[N];
    inline int find (int x) {
        return x == fa[x] ? x : fa[x] = find (fa[x]);
    }
    inline void merge (int x, int y) {
        fa[find (x)] = find (y);
    }
    void main () {
        for (int i = 1; i <= n; i ++ ) fa[i] = i, vis[i] = 0;
        for (int i = 1; i <= n; i ++ ) {
            for (int j = 1; j <= n; j ++ ) {
                if (!vis[j] && (i == n || find (j) != find (p[i]))) {
                    ans[i] = j; vis[j] = 1; merge (j, p[i]);
                    break;
                }
            }
        }
        for (int i = 1; i <= n; i ++ ) printf ("%d%c", ans[i], i == n ? '\n' : ' ');
    }
}

标签:rt,删边,int,点权,find,fa,2019,树上,CSP
来源: https://www.cnblogs.com/Hock/p/12381618.html