草庐IT

Codeforces 1646 D. Weight the Tree

4VDP 2023-03-28 原文

题意

给你n个节点的树,让你给每个节点进行赋值,并且赋的值需要为正整数;
同时当一个节点的值等于所有邻居节点的值的和时,这个点为好点;
求出一组赋值情况,满足树的好点个数最大化的同时,所有节点赋值的总和最小;

思路

1. 显然无法存在两个好点相邻存在的情况(除非只有两个节点);

2. 对于坏点直接赋值为1即可;

3. 可以树形dp解决,f[x][0/1][0/1],第一维代表以x为根,第二维代表是否为好点,第三维代表是好点的个数/子树节点值的总和

代码

#include<bits/stdc++.h>

using namespace std;
vector<int> g[200005];
int f[200005][2][2];
long long ans[200005];
int cnt[200005];

void dp(int x, int fa) {
    f[x][1][0] = 1;//好点个数
    f[x][1][1] = g[x].size();//累计
    f[x][0][0] = 0;
    f[x][0][1] = 1;
    for (auto k: g[x]) {
        if (k == fa)continue;
        dp(k, x);
    }
    for (auto k: g[x]) {
        if (k == fa)continue;
        f[x][1][0] += (f[k][0][0]);
        f[x][1][1] += (f[k][0][1]);
    }
    for (auto k: g[x]) {
        if (k == fa)continue;
        if (f[k][0][0] > f[k][1][0]) {
            f[x][0][0] += f[k][0][0];
            f[x][0][1] += f[k][0][1];
        } else if (f[k][0][0] == f[k][1][0]) {
            f[x][0][0] += f[k][0][0];
            f[x][0][1] += min(f[k][0][1], f[k][1][1]);
        } else {
            f[x][0][0] += f[k][1][0];
            f[x][0][1] += f[k][1][1];
        }
    }
}

void down(int x, int fa, int now) {
    ans[x] = now;
    if (now == 1) {
        for (auto k: g[x]) {
            if (k == fa)continue;
            down(k, x, 0);
        }
    } else {
        for (auto k: g[x]) {
            if (k == fa)continue;
            if (f[k][0][0] > f[k][1][0]) {
                down(k, x, 0);
            } else if (f[k][0][0] == f[k][1][0]) {
                if (f[k][0][1] < f[k][1][1])
                    down(k, x, 0);
                else
                    down(k, x, 1);
            } else {
                down(k, x, 1);
            }
        }
    }
}

void run() {
    int n;
    cin >> n;
//    for (int i = 1; i <= n; i++)g[i].clear(), f[i] = 0, ans[i] = 0;
    for (int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        g[x].emplace_back(y);
        g[y].emplace_back(x);
    }
    if (n == 2) {
        cout << 2 << ' ' << 2 << '\n';
        cout << 1 << ' ' << 1 << '\n';
        return;
    }
    dp(1, 0);
    bool flag = 1;
    if (f[1][0][0] > f[1][1][0])flag = 0;
    if (f[1][0][0] == f[1][1][0] && f[1][0][1] < f[1][1][1])flag = 0;
    down(1, 0, flag);
    cout << f[1][flag][0] << ' ' << f[1][flag][1] << '\n';
    for (int i = 1; i <= n; i++) {
        if (ans[i])cout << g[i].size() << ' ';
        else cout << 1 << ' ';
    }
}

int main() {
    run();
    return 0;
}

有关Codeforces 1646 D. Weight the Tree的更多相关文章

  1. Educational Codeforces Round 146 (Rated for Div. 2)(B,E详解) - 2

    题外话:抑郁场,开局一小时只出A,死活想不来B,最后因为D题出锅ura才保住可怜的分。但咱本来就写不到DB-LongLegs(数论)本题题解法一学自同样抑郁的知乎作者幽血魅影的题解,有讲解原理。法二来着知乎巨佬cup-pyy(大佬说《不难发现》呜呜)题意三种操作:向上走mmm步向右走mmm步给自己一次走的步数加111,即使得m=m+1m=m+1m=m+1问从(0,0)(0,0)(0,0)走到(a,b)(a,b)(a,b)的最小操作次数,值得注意的是操作三不可逆。解析假设我们最终一步的大小增长到mmm,那么在这个过程中我能以[1,m][1,m][1,m](当步数增长到该数时)之间的任何数字向上或

  2. Codeforces Round 866 (Div. 2) - 2

    A.Yura'sNewName题意:给出一个仅由_或^组成的字符串,你可以在任意位置添加_或^字符,使得字符串满足:任意字符要么属于^_^的一部分,要么属于^^的一部分。求最少添加的字符数量。分析:对于_我们只需处理没有组成^_^的_:①如果_在首位置且左边没有^则添加^②如果_在尾位置且右边没有^则添加^③如果_在中间部分且右边没有^则添加^当字符串只有一个^时末尾添加一个^code:#includeusingnamespacestd;intmain(){ std::ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); intt; cin

  3. Educational Codeforces Round 145 Div. 2 题解 - 2

    目录A.Garland(签到)题面翻译思路:代码B.PointsonPlane(数学)题面翻译思路:代码C.SumonSubarray(构造)题面翻译:思路:代码D.BinaryStringSorting题面翻译思路:代码A.Garland(签到)Youhaveagarlandconsistingof 4 coloredlightbulbs,thecolorofthe i-thlightbulbis si.Initially,allthelightbulbsareturnedoff.Yourtaskistoturnallthelightbulbson.Youcanperformthefollo

  4. Educational Codeforces Round 145 Div. 2 题解 - 2

    目录A.Garland(签到)题面翻译思路:代码B.PointsonPlane(数学)题面翻译思路:代码C.SumonSubarray(构造)题面翻译:思路:代码D.BinaryStringSorting题面翻译思路:代码A.Garland(签到)Youhaveagarlandconsistingof 4 coloredlightbulbs,thecolorofthe i-thlightbulbis si.Initially,allthelightbulbsareturnedoff.Yourtaskistoturnallthelightbulbson.Youcanperformthefollo

  5. Educational Codeforces Round 132 div.2 A-F题解 - 2

    视频讲解:TBDA.ThreeDoors题目大意有333个门和333把对应的钥匙。其中222把钥匙分别在222扇门后,111把在手上。打开门才能获得门后的钥匙,问能否打开所有的门。题解判断前两次开的门后,是否有钥匙即可。参考代码#includeusingnamespacestd;typedeflonglongll;intmain(){ intT,x,a[5],now; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&x,&a[1],&a[2],&a[3]); now=3^2^1^a[1]^a[2]^a[3]; if(a[now]==0||a[

  6. Educational Codeforces Round 132 div.2 A-F题解 - 2

    视频讲解:TBDA.ThreeDoors题目大意有333个门和333把对应的钥匙。其中222把钥匙分别在222扇门后,111把在手上。打开门才能获得门后的钥匙,问能否打开所有的门。题解判断前两次开的门后,是否有钥匙即可。参考代码#includeusingnamespacestd;typedeflonglongll;intmain(){ intT,x,a[5],now; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&x,&a[1],&a[2],&a[3]); now=3^2^1^a[1]^a[2]^a[3]; if(a[now]==0||a[

  7. Codeforces CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!) A-D 题解 - 2

    A.Two0-1Sequences 大致翻译:两个长度为n和m的二进制序列a和b(题目保证n>=m)两个操作:op1: 改变a(2)为min(a(1),a(2)),并且移除a(1)op2: 改变a(2)为max(a(1),a(2)),并且移除a(1)每次操作后,原先的a(i)变成a(i+1),长度减少1,即前移。  a二进制序列能否通过这两个操作变成b二进制序列?解题思路:刚开始想的是判断a2后缀跟a1后缀是否相同,再判断,a1前面有没有1和0(因为有1和0,就表示op1和op2可以随意完成)。写的时候又陆陆续续发现需要几个特判,想a1长度为1等。于是就debug,慢慢发现只要前面有a2的第一

  8. Codeforces CodeTON Round 2 (Div. 1 + Div. 2, Rated, Prizes!) A-D 题解 - 2

    A.Two0-1Sequences 大致翻译:两个长度为n和m的二进制序列a和b(题目保证n>=m)两个操作:op1: 改变a(2)为min(a(1),a(2)),并且移除a(1)op2: 改变a(2)为max(a(1),a(2)),并且移除a(1)每次操作后,原先的a(i)变成a(i+1),长度减少1,即前移。  a二进制序列能否通过这两个操作变成b二进制序列?解题思路:刚开始想的是判断a2后缀跟a1后缀是否相同,再判断,a1前面有没有1和0(因为有1和0,就表示op1和op2可以随意完成)。写的时候又陆陆续续发现需要几个特判,想a1长度为1等。于是就debug,慢慢发现只要前面有a2的第一

  9. codeforces 54B Cutting Jigsaw Puzzle题解 - 2

    详情请见:CSDN阿史大杯茶  https://blog.csdn.net/weixin_66946161/article/details/126093709题目意思本题主要意思就是切成一个个小块(小块的面积相同,但小块不相同),使小块之间互不相等,而且旋转之后相同,也算小块相同!例:ABCACDDB这两个是相同的!最后输出一共可以有多少种切法,使他们互不相等,然后输出切出的最小块(这里要注意如果面积相等,则输出a小的那一个)比如说:和,是要输出!思路:这道题主要就是取块以及旋转判断:取块:这个很简单,只需双重for循环,不停的枚举中的a和b,如果a或b不能被N或M整除,那么是不行的所以要co

  10. codeforces 54B Cutting Jigsaw Puzzle题解 - 2

    详情请见:CSDN阿史大杯茶  https://blog.csdn.net/weixin_66946161/article/details/126093709题目意思本题主要意思就是切成一个个小块(小块的面积相同,但小块不相同),使小块之间互不相等,而且旋转之后相同,也算小块相同!例:ABCACDDB这两个是相同的!最后输出一共可以有多少种切法,使他们互不相等,然后输出切出的最小块(这里要注意如果面积相等,则输出a小的那一个)比如说:和,是要输出!思路:这道题主要就是取块以及旋转判断:取块:这个很简单,只需双重for循环,不停的枚举中的a和b,如果a或b不能被N或M整除,那么是不行的所以要co

随机推荐