📅  最后修改于: 2023-12-03 15:42:12.530000             🧑  作者: Mango
该问题是关于树的处理。问题给出了一个具有N个节点的树,其中每个节点都有一个权重。对于该树的任何一个节点,从该节点出发的最大权重子树大小定义为从该节点出发,其所有后代节点权重之和不超过该子树的根节点的权重之和。问题要求找到最大的节点个数。
为解决该问题,可以使用以下算法:
下面是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)。