📜  门| GATE CS 2020 |问题30(1)

📅  最后修改于: 2023-12-03 15:42:12.530000             🧑  作者: Mango

GATE CS 2020 | 问题30

该问题是关于树的处理。问题给出了一个具有N个节点的树,其中每个节点都有一个权重。对于该树的任何一个节点,从该节点出发的最大权重子树大小定义为从该节点出发,其所有后代节点权重之和不超过该子树的根节点的权重之和。问题要求找到最大的节点个数。

为解决该问题,可以使用以下算法:

  1. 对树进行后序遍历,先处理其子节点,再处理父节点。
  2. 对于每个节点,计算其子树的权重之和S和其最大的子树大小maxSize(不超过节点权重),然后计算其父节点的最大子树大小maxSize'。依照这种方式,递归地计算每个节点的最大子树大小。
  3. 对于每个节点,其最大子树大小可以是自身的大小(如果该节点权重大于所有后代的权重之和)或者是其子节点的最大子树大小。
  4. 最终,对于所有节点的最大子树大小取最大值,即为所求。

下面是C++代码实现:

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

int n, u[100010], v[100010], w[100010], son[100010], nxt[100010], head[100010], num;
long long sum[100010], f[100010], res;

inline int read()
{
    int x = 0; char ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = (x<<1) + (x<<3) + (ch^48), ch = getchar();
    return x;
}

void add(int x,int y)
{
    u[++num] = x; v[num] = y; nxt[num] = head[x]; head[x] = num;
}

void dfs_sum(int x,int pre)
{
    sum[x] = w[x];
    for (int i = head[x]; i; i = nxt[i]) {
        int y = v[i];
        if (y==pre) continue;
        dfs_sum(y, x);
        sum[x] += sum[y];
    }
}

void dfs(int x,int pre)
{
    for (int i = head[x]; i; i = nxt[i]) {
        int y = v[i];
        if (y==pre) continue;
        dfs(y, x);
        if (sum[y] > sum[son[x]]) son[x] = y;
    }
    sum[x] = w[x];
    for (int i = head[x]; i; i = nxt[i]) {
        int y = v[i];
        if (y==pre || y==son[x]) continue;
        sum[x] += sum[y];
        for (int j = 1;j <= min(sum[x], res);j++) {
            f[j] = max(f[j], f[j-1] + f[j-1]-f[j-1-min(son[x]==0?0:min(sum[son[x]], j-1), j-1-min(y==0?0:min(sum[y], j-1)))]); 
        }
    }
    if (son[x]) sum[x] += sum[son[x]];
    if (sum[x] <= res) {
        for (int i = 1;i <= sum[x];i++) f[i] = i;
        for (int i = sum[x]+1;i <= res;i++) f[i] = 0;
        return;
    }
    for (int i = 1;i <= res;i++) f[i] = 0;
    dfs(son[x], x);
    for (int i = 1;i <= min(res, sum[son[x]]);i++) f[i] = f[i-1];
    for (int i = 1;i <= min(res-sum[son[x]], sum[x]-sum[son[x]]);i++) {
        f[i] = max(f[i], f[i-1] + f[i-1]-f[i-1-min(sum[son[x]], i-1)]);
    }
}

int main()
{
    n = read(), res = 1ll<<read();
    for (int i = 1;i < n;i++) {
        int x = read(), y = read(), z = read();
        add(x, y), add(y, x);
        w[x] = w[y] = z;
    }
    dfs_sum(1, 0);
    dfs(1, 0);
    for (int i = res;i >= 0;i--) {
        if (f[i] <= res) {
            printf("%d\n", i);
            return 0;
        }
    }
    return 0;
}

这个算法的时间复杂度为O(N^2logN),空间复杂度为O(N)。