【Codeforces 1338B】Edge Weight Assignment

题目链接

链接

翻译

让你构造一棵树,使得任意两个叶子节点之间路径的权重异或和为 \(0\)

并且,树中用到的边的权重的不同值的个数设为 \(f\),让你求 \(f\) 的最大值和最小值。

题解

最小值不会超过 \(3\)

可以转化为是在给每个点标记数字,然后边上的权重就是连接它们两个点上标的数字的异或值。

这样的话,只要保证任意两个叶子节点上标记的数字是一样的,就能满足题意了。

我们可以把所有的叶子都标记上 \(1\),然后中间的非叶子节点标记上 \(2\)\(3\) (因为权重要大于 \(0\),所以相邻两个节点权重不能相同)。

可以想见,如果只用 \(1\)\(2\) 就能让树上相邻两个点数字不同(且叶子节点数字都相同),那么只会产生一种边权,最小答案就可以为 \(1\),否则 \(3\)

个数字,两两异或最多组成 \(3\) 种权重。因此最小答案的最大值就为 \(3\)

关于等于 \(1\) 的判断,可以选择一个叶子节点作为根进行 \(dfs\) 然后求出它到其他叶子节点的距离,如果满足这些到叶子节点的距离都为偶数。那么就可以

\(1\),因为任意两个节点的树上距离为 \(dis(x,root)+dis(y,root)-2*dis(lca(x,y),root)\)

对于最大值的情况,显然只要让边权为 \(2^0,2^1,2^2....\) 然后和叶子节点连接的那个边权等于前面这些数字的和就好了,即二进制全为 \(1\)

这样的话,理想情况下我们所有边的边权都可以不同。

但是理想是丰满的,现实是残酷的。对于连在同一个节点上的两个叶子节点,它们俩和这个节点的边权必然是相同的,所以要减掉。

直接给结论吧,最大值为 \(n-1-cntLeaf+cntSpecial\) 这里的 \(cntSpecial\) 是所有和叶子节点有连接的点的个数。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int N = 1e5;

int n;
int du[N+10],dis[N+10];
vector<int> g[N+10];

//[6]写dfs
void dfs(int x,int fa){
    for (int y:g[x]){
        if (y==fa){
            continue;
        }
    //[7]统计到这个点的距离
        dis[y] = dis[x] + 1;
        dfs(y,x);
    }
}

int main(){
    // freopen("C://1.cppSourceProgram//rush.txt","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0);
    //step1 输入数据
    cin >> n;
    for (int i = 1;i <= n-1; i++){

        int x,y;
        cin >> x >> y;
        //step2 统计度信息
        du[x]++;du[y]++;
        // 5 简图
        g[x].push_back(y);
        g[y].push_back(x);
    }
    //step3 找个度为 1 的叶子当根
    int root = 1;
    for (int i = 2;i <= n; i++){
        if (du[i] == 1){
            root = i;
        }
    }
    //step4 从root 开始做 dfs

    dfs(root,-1);

    int mi = 1;
    //[8]看看是不是到所有叶子节点的距离都为偶数
    for (int i = 1;i <= n; i++){
        if (dis[i]%2!=0 && du[i] == 1){
            mi = 3;
        }
    }
    cout << mi <<" ";
    //[9] 找和叶子节点相邻的节点数目
    int cnt1 = 0;
    //[10] 叶子节点数
    int cntLeaf = 0;
    for (int i = 1;i <= n; i++){
        if (du[i] == 1){
            cntLeaf++;
        }
        int ok = 0;
        for(int y:g[i]){
            if (du[y] == 1){
                ok=1;
            }
        }
        cnt1+=ok;
    }
    // [11] math
    int ma = n - 1 - cntLeaf + cnt1;
    cout << ma << endl;
    return 0;
}

posted @ 2020-12-16 13:40  AWCXV  阅读(93)  评论(0编辑  收藏  举报