[CF1338B] Edge Weight Assignment

题目描述

源网站

简化描述:给定一棵 \(n\) 个点的无根树,要求给每条边分配一个正整数权值,使得任意两个叶子节点之间路径上的边权异或值为 \(0\)。求最少要多少种不同权值,以及最多可以使用多少种不同权值。填入的边权值可以为任意大,\(3\leq n\leq 10^5\)

解题思路

求解最少

如果任意两个叶子节点之间都是偶数条边,那么我们只需要把所有边填上同一个值即可。如果出现了奇数条边的路径呢?

这里我们需要几个命题:

我们先将两个节点 \(u\)\(v\) 之间路径的边数记为 \(D\{u,v\}\),叶子节点集合记为 \(\mathbb{L}\),而根节点记为 \(R\)

命题一:对于一棵节点数 \(n\geq 3\) 的树,\(D\{u,v\}\geq 2\)\(u,v\in\mathbb{L}\)

  • 证明:如果 \(\exists D\{u,v\}=1\)\(u,v\in\mathbb{L}\),结合 \(\mathbb{L}\) 的节点度数为 \(1\) 得知这棵树节点只有 \(2\) 个,导出矛盾。

命题二:如果 \(D\{u,v\}=2k+3\)\(u,v\in\mathbb{L}\)\(k\in\mathbb{N}\),那么使这些边权值异或为 \(0\) 的不同权值个数最小为 \(3\)

  • 证明:将 \(2k+1\) 条边的权值设置为相同权值,对余下 \(2\) 条边根据异或关系分配不同的权值即可。如若给 \(2k+2\) 条边分配相同权值,则最终异或值必为余下边的权值大小,而不等于 \(0\)

考虑好了两叶子节点的路径(可以称为链),那么我们就需要考虑多链相交的情况了。

命题三:\(D\{u,v\}\)\(D\{R,u\}+D\{R,v\}\) 奇偶性相同。

  • 证明:假设 \(u,v\) 的最近公共祖先节点为 \(A_{u,v}\),则有 \(D\{R,u\}+D\{R,v\}=2D\{R,A_{u,v}\}+D\{A_{u,v},u\}+D\{A_{u,v},v\}\)。不难知道 \(D\{A_{u,v},u\}+D\{A_{u,v},v\}=D\{u,v\}\),而 \(2D\{R,A_{u,v}\}\) 恒为偶数,所以 \(D\{u,v\}\)\(D\{R,u\}+D\{R,v\}\) 奇偶性相同。

答案:如果 \(D\{R,u\}\) 均为偶数,\(u\in\mathbb{L}\),则答案为 \(1\),否则答案为 \(3\)

  • 证明:根据命题三,如果满足均为偶数的条件,那么必然有 \(D\{u,v\}\) 均为偶数,\(u,v\in\mathbb{L}\)。不然,根据命题二,答案至少为 \(3\)。下面证明答案可以取到 \(3\):对于 \(R,u\in\mathbb{L}\),考虑命题二中余下的 \(2\) 个不同权值,将它们分别分配到与 \(R,u\) 相连的边。再考虑任意 \(v\in\mathbb{L}\),如果 \(D\{R,v\}\) 为偶数,那么与 \(v\) 相连的边权等于与 \(R\) 相连的,根据命题三,此时 \(D\{u,v\}\) 为奇数,满足此构造;如果 \(D\{R,v\}\) 为奇数,那么与 \(v\) 相连的边权等于与 \(u\) 相连的,根据命题三,此时 \(D\{u,v\}\) 为偶数,满足此构造。于是我们就找到了答案为 \(3\) 的一种构造,结论成立。

那么,如何编程来寻找奇数的 \(D\) 呢?我们需要确定好 \(R\in\mathbb{L}\),如果存在 \(u,v\in\mathbb{L}\),其 \(D\{u,v\}\) 为奇数,那么根据命题三,\(D\{R,u\},D\{R,v\}\) 必有一个奇数。所以只需一次 DFS 遍历,以 \(R\) 节点为深度 \(0\),寻找是否存在奇数深度叶子节点即可。

求解最多

同样的,这里我们也需要几个命题:

我们记异或运算符为:\(\otimes\),记一组数 \(a_i\) 的异或和为 \(\prod_{\otimes} a\),记 \(u,v\in\mathbb{L}\) 之间边权值异或和为 \(\prod_{\otimes}\{u,v\}\)

命题四:给定数 \(t\) 可以找出无数种不同的一组数 \(a_i\)\(|a|\geq 2\)),使得 \(\prod_{\otimes} a=t\)

  • 证明:从二进制角度考虑,保证 \(t\) 对应的二进制位最后异或结束依然存在,而其它各位最后异或结束后被消去即可。由于所选数没有上限,这样的可能有无数种。如果 \(|a|=1\) 则只有 \(a_1 = t\) 一种可能。

那么根据命题四,我们在任意节点 \(u\) 时,如果其儿子中有 \(x\) 个非叶子节点和 \(y\) 个叶子节点,那么可以新产生的不同的数的个数为 \(x+[y>0]\),因为其所有叶子节点的值都必须相等。将这些贡献累加得到答案。特别的,如果根节点也是叶子节点,那么必须判断其儿子是否有叶子节点,如果有,则答案应减少 \(1\)(上述流程操作完毕后)。

代码一览

#include <bits/stdc++.h>
using namespace std;
vector<int> G[100005];
int n, l, r;
int leaves;
int rtnd;
bool have_leaves[100005];
int f;
bool jishu;
bool vis[100005];
bool dfs(int u, int dpth)
{
    int s = G[u].size();
    if(s == 1 && vis[G[u][0]])
    {
        if(dpth&1)
            jishu = true;
        leaves += 1;
        return true;
    }
    bool haveleaf = false;
    vis[u] = true;
    for(register int i = 0 ; i < s; i += 1)
    {
        int v = G[u][i];
        if(vis[v])
            continue;
        if(dfs(v, dpth+1))
        {
            if(!haveleaf)
                f += 1, haveleaf = true;
        }
        else
        {
            if(u != rtnd)
                f += 1;
            else if(!have_leaves[v])
                f += 1;
        }
    }
    if(haveleaf)
        have_leaves[u] = true;
    return false;
}
int main()
{
    register int i;
    cin >> n;
    for(i = 1; i < n; i += 1)
    {
        cin >> l >> r;
        G[l].push_back(r);
        G[r].push_back(l);
    }
    for(rtnd = 1; rtnd <= n; rtnd += 1)
        if(G[rtnd].size() == 1)
        {
            dfs(rtnd, 0);
            leaves += 1;
            break;
        }
    cout << (jishu?3:1) << ' ' << f;
    return 0;
}
posted @ 2021-03-14 00:12  孤独·粲泽  阅读(64)  评论(0编辑  收藏  举报