3252: 攻略
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 469 Solved: 194
[Submit][Status][Discuss]
Description
题目简述:树版[k取方格数]
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”
Input
第一行两个正整数n,k
第二行n个正整数,表示每个场景的价值
以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
保证场景1为根节点
Output
输出一个整数表示答案
Sample Input
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
4 3 2 1 1
1 2
1 5
2 3
2 4
Sample Output
10
HINT
对于100%的数据,n<=200000,1<=场景价值<=2^31-1
Source
我太zz了,竟然没想出来。。。
一直觉得一个一个爬上去太慢了,看了题解发现自己是个zz,一共只删n个,也就是说只用爬n次就行了
那么dfs序+线段树 每次给子树全部减这个点的值 然后把这个点的值清0 用线段树维护最大值和位置。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll, int> PII; const int N = 200010; struct edge { int nxt, to; } e[N << 1]; int n, k, cnt = 1, tot; ll ans; int head[N], dfn[N], low[N], fa[N], mp[N]; ll v[N], w[N], tag[N << 2]; PII tree[N << 2]; void link(int u, int v) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].to = v; } namespace seg { void pushdown(int x) { if(!tag[x]) return; tree[x << 1].first += tag[x]; tree[x << 1 | 1].first += tag[x]; tag[x << 1] += tag[x]; tag[x << 1 | 1] += tag[x]; tag[x] = 0; } void build(int l, int r, int x) { if(l == r) { tree[x].first = w[mp[l]]; tree[x].second = mp[l]; return; } int mid = (l + r) >> 1; build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1); if(tree[x << 1].first > tree[x << 1 | 1].first) tree[x] = tree[x << 1]; else tree[x] = tree[x << 1 | 1]; } void update(int l, int r, int x, int a, int b, int num) { if(l > b || r < a) return; if(l >= a && r <= b) { tree[x].first += num; tag[x] += num; return; } pushdown(x); int mid = (l + r) >> 1; update(l, mid, x << 1, a, b, num); update(mid + 1, r, x << 1 | 1, a, b, num); if(tree[x << 1].first > tree[x << 1 | 1].first) tree[x] = tree[x << 1]; else tree[x] = tree[x << 1 | 1]; } } using namespace seg; void dfs(int u, int last, ll sum) { dfn[u] = ++tot; mp[tot] = u; w[u] = sum; for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last) { fa[e[i].to] = u; dfs(e[i].to, u, sum + v[e[i].to]); } low[u] = tot; } void change(int pos) { while(v[pos]) { update(1, n, 1, dfn[pos], low[pos], -v[pos]); v[pos] = 0; pos = fa[pos]; } } int main() { scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++i) scanf("%lld", &v[i]); for(int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); link(u, v); link(v, u); } ans = v[1]; v[1] = 0; dfs(1, 0, 0); build(1, n, 1); while(k--) { PII x = tree[1]; ans += x.first; change(x.second); } printf("%lld\n", ans); return 0; }