noip模擬賽 旅行
阿新 • • 發佈:2017-11-01
cloc pan blog color ace images while cstring using
分析:一個貪心的想法是每次找到根的點權和最大的點進行操作,關鍵是怎麽維護.每次找最大值,修改後會對這條鏈上每個點的子樹上的點造成影響,可以用線段樹來維護.找最大值就是區間求最大值嘛,對子樹進行操作利用dfs序維護一下就好了.記錄一下最大值的位置,每次從這個位置向上跳並對它的子樹進行修改直到當前點的點權為0.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 200010; typedef long long ll; int n, k, a[maxn], fa[maxn],head[maxn], to[maxn], nextt[maxn],tot = 1, d[maxn], l[maxn], r[maxn], pos[maxn], dfs_clock; int maxx[maxn << 2], tag[maxn << 2], p[maxn << 2]; ll ans; void add(int x, int y) { to[tot] = y; nextt[tot] = head[x]; head[x]= tot++; } void dfs(int u, int from, int dist) { d[u] = dist; l[u] = ++dfs_clock; pos[dfs_clock] = u; for (int i = head[u]; i; i = nextt[i]) { int v = to[i]; if (v != from) { dfs(v, u, dist + a[v]); fa[v] = u; } } r[u]= dfs_clock; } void pushup(int o) { if (maxx[o * 2] > maxx[o * 2 + 1]) { maxx[o] = maxx[o * 2]; p[o] = p[o * 2]; } else { maxx[o] = maxx[o * 2 + 1]; p[o] = p[o * 2 + 1]; } } void build(int o, int l, int r) { if (l == r) { maxx[o] = d[pos[l]]; p[o] = pos[l]; return; } int mid = (l + r) >> 1; build(o * 2, l, mid); build(o * 2 + 1, mid + 1, r); pushup(o); } void pushdown(int o) { if (tag[o] != 0) { tag[o * 2] += tag[o]; tag[o * 2 + 1] += tag[o]; maxx[o * 2] += tag[o]; maxx[o * 2 + 1] += tag[o]; tag[o] = 0; } } void update(int o, int l, int r, int x, int y,int v) { if (x <= l && r <= y) { maxx[o] += v; tag[o] += v; return; } pushdown(o); int mid = (l + r) >> 1; if (x <= mid) update(o * 2, l, mid, x, y, v); if (y > mid) update(o * 2 + 1, mid + 1, r, x, y, v); pushup(o); } void change(int x) { while (a[x]) { update(1, 1, n, l[x], r[x], -a[x]); a[x] = 0; x = fa[x]; } } int main() { scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } dfs(1, 0, a[1]); build(1, 1, n); for (int i = 1; i <= k; i++) { ans += maxx[1]; change(p[1]); } printf("%lld\n", ans); return 0; }
noip模擬賽 旅行