发布于 

世界线修复计划

世界线修复计划

HITwh OJ 43

题目来源: HITwh OJ

思路

其实总体而言,是一个比较水的题目。题目要求将一个树分割为两个子树,并且两个子树的各点权值之和的差最小。

很明显,我们可以在建树过程中直接记录以每一个节点为根节点的子树的权值和,然后再枚举一边,找到和所有节点的总权值的一半最为接近的即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <cstdio>
#include <iostream>

struct Edge
{
trueint from,to,next;
trueEdge(int from=0,int to=0,int next=0):from(from),to(to),next(next) {}
}e[500000];

int f[300000];
long long cnt[300000];
int h[300000];
bool flag[300000];

int build(int x)
{
trueflag[x] = true;
truecnt[x] = h[x];

trueint v = f[x];
truewhile (v)
true{
truetrueif (!flag[e[v].to])
truetruetruecnt[x] += build(e[v].to);

truetruev = e[v].next;
true}

truereturn cnt[x];
}

long long Abs(long long x)
{
truereturn x>0?x:-x;
}

int main()
{
trueint T;
truescanf("%d",&T);

truewhile (T--)
true{
truetrueint n;
truetruescanf("%d",&n);

truetruefor (int i = 1; i<=n; i++)
truetrue{
truetruetruef[i] = 0;
truetruetrueflag[i] = false;
truetrue}

truetruefor (int i = 1; i<n; i++)
truetrue{
truetruetrueint x,y;
truetruetruescanf("%d%d",&x,&y);
truetruetruee[2*i-1] = Edge(x,y,f[x]);
truetruetruef[x] = 2*i - 1;
truetruetruee[2*i] = Edge(y,x,f[y]);
truetruetruef[y] = 2*i;
truetrue}

truetruelong long sum = 0;
truetruefor (int i = 1; i<=n; i++)
truetrue{
truetruetruescanf("%d",&h[i]);
truetruetruesum += h[i];
truetrue}

truetruebuild(1);

truetruelong long ans = sum;
truetruefor (int i = 1; i<=n; i++)
truetruetrueif ( Abs(sum-2*cnt[i]) < ans)
truetruetruetrueans = Abs(sum-2*cnt[i]);

truetruestd::cout << ans << std::endl;
true}
}

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站由 [@Songer](https://blog.songer.xyz/) 创建,使用 Stellar 作为主题。