CQOI2009 叶子的染色

题目链接

Solution

结论一:根节点的选择不影响答案。

证明:(因为大佬的证明都看不懂,这里给出一个很菜的证明)

假设 1,2 是两个相邻的节点,现在以 1 为根。两节点的子树如图 [1] 所示。现在子树 A 依赖 1 的染色,子树 B 依赖 2 的染色。

现在考虑将两个节点交换(2 为根,1 为 2 的子树),如图 [2] 所示。两者的依赖关系不变。

那么如果节点 1 未染色呢?手推一下答案也是一样的。

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;

const int N = 23333;
const LL INF = 1e16;
struct edge { LL nxt, to; } e[N * 66];
LL n, m, root, cnt = 0, c[N], du[N], head[N], f[N][2];

void add(LL x, LL y)
{
    e[++cnt] = (edge) { head[x], y };
    head[x] = cnt;
}

void dfs(LL x, LL fa)
{
    if(x <= n) f[x][c[x] ^ 1] = INF;
    for(int i = head[x]; i; i = e[i].nxt)
    {
        LL v = e[i].to;
        if(v == fa) continue;
        dfs(v, x);
        f[x][0] += min(f[v][0] - 1, f[v][1]);
        f[x][1] += min(f[v][1] - 1, f[v][0]);
    }
}

int main()
{
    scanf("%lld%lld", &m, &n);
    memset(f, 0, sizeof(f));
    memset(du, 0, sizeof(du));
    memset(head, 0, sizeof(head));
    for(int i = 1; i <= n; i++) scanf("%lld", &c[i]);
    for(LL u, v, i = 1; i < m; i++)
    {
        scanf("%lld%lld", &u, &v);
        add(u, v), add(v, u);
        du[u]++, du[v]++;
    }
    for(int i = 1; i <= m; i++) f[i][0] = f[i][1] = 1;
    for(int i = n + 1; i <= m; i++)
        if(du[i] > 1) { root = i; break; }
    dfs(root, 0);
    printf("%lld", min(f[root][0], f[root][1]));
    return 0;
}
posted @ 2020-09-16 17:22  Nyxia  阅读(117)  评论(0编辑  收藏  举报