Description
小 \(A\) 走到一个山脚下,准备给自己造一个小屋。这时候,小 \(A\) 的朋友(op,又叫管理员)打开了创造模式,然后飞到山顶放了格水。于是小 \(A\) 面前出现了一个瀑布。作为平民的小A只好老实巴交地爬山堵水。那么问题来了:我们把这个瀑布看成是一个𝑛个节点的树,每个节点有权值(爬上去的代价)。小A要选择一些节点,以其权值和作为代价将这些点删除(堵上),使得根节点与所有叶子结点不连通。问最小代价。不过到这还没结束。小A的朋友觉得这样子太便宜小A了,于是他还会不断地修改地形,使得某个节点的权值发生变化。不过到这还没结束。小A觉得朋友做得太绝了,于是放弃了分离所有叶子节点的方案。取而代之的是,每次他只要在某个子树中(和子树之外的点完全无关)。于是他找到你。
\(n\le 2\times 10^5, m\le 2\times 10^5\)
Solution
第一眼动态dp,还真是的,就当锻炼码力。
首先有转移
\[
dp[u] = min\{\sum_{v\in son(u)}dp[v],\ a[u]\}
\]
记 \(son[u]\) 为u的重儿子(和上面的son(u)不是同一个东西),\(g[u]\) 为 u 虚儿子的 \(dp\) 值之和。
\[ dp[u] = \min\{a[u], f[son[u]] + g[u]\} \]
把这个东西放在重链上,假设我们维护了重链上每个点的 \(g[u]\) 和 \(dp[u]\) 那么查询x就查这条重链以x开头的一个类似于前缀的最小值。
修改的时候就暴力往上跳链修改点,会更新到一些点的 \(g[u]\),这些u就是两条链的交接处。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <fstream> typedef long long LL; typedef unsigned long long uLL; #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define MP(x, y) std::make_pair(x, y) #define DE(x) cerr << x << endl; #define debug(...) fprintf(stderr, __VA_ARGS__) #define GO cerr << "GO" << endl; using namespace std; inline void proc_status() { ifstream t("/proc/self/status"); cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl; } inline int read() { register int x = 0; register int f = 1; register char c; while (!isdigit(c = getchar())) if (c == '-') f = -1; while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar())); return x * f; } template<class T> inline void write(T x) { static char stk[30]; static int top = 0; if (x < 0) { x = -x, putchar('-'); } while (stk[++top] = x % 10 xor 48, x /= 10, x); while (putchar(stk[top--]), top); } template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; } template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; } const int maxN = 2e5 + 2; #define ls (x << 1) #define rs (x << 1 | 1) #define Lson ls, l, mid #define Rson rs, mid + 1, r struct Node { LL g, f; Node() { } Node(LL g, LL f) : g(g), f(f) { } Node operator + (const Node &B) const { return Node(g + B.g, min(f, g + B.f)); } } t[maxN << 2], val[maxN]; void pushup(int x) { t[x] = t[ls] + t[rs]; } void build(int x, int l, int r) { if (l == r) { t[x] = val[l]; return; } int mid = l + r >> 1; build(Lson); build(Rson); pushup(x); } void modify(int x, int l, int r, int p) { if (l == r) { t[x] = val[l]; return; } int mid = l + r >> 1; if (p <= mid) modify(Lson, p); else modify(Rson, p); pushup(x); } Node query(int x, int l, int r, int L, int R) { if (L <= l and r <= R) { return t[x]; } int mid = l + r >> 1; if (R <= mid) return query(Lson, L, R); if (mid < L) return query(Rson, L, R); return query(Lson, L, mid) + query(Rson, mid + 1, R); } int n; int ver[maxN << 1], nxt[maxN << 1], head[maxN], tot; int fa[maxN], top[maxN], son[maxN], size[maxN], dfn[maxN], butt[maxN], dfst; void link(int u, int v) { ver[++tot] = v, nxt[tot] = head[u], head[u] = tot; } void dfs1(int u, int f) { fa[u] = f; size[u] = 1; for (int i = head[u]; i; i = nxt[i]) if (ver[i] != f) { dfs1(ver[i], u); size[u] += size[ver[i]]; if (size[son[u]] < size[ver[i]]) son[u] = ver[i]; } } LL dp[maxN], a[maxN]; void dfs2(int u, int topf) { dp[u] = 0; dfn[u] = ++dfst; top[u] = topf; if (son[u]) { dfs2(son[u], topf); dp[u] += dp[son[u]]; } else butt[topf] = dfst, dp[u] = 1ll << 50; for (int i = head[u]; i; i = nxt[i]) if (ver[i] != fa[u] and ver[i] != son[u]) { dfs2(ver[i], ver[i]); dp[u] += dp[ver[i]]; val[dfn[u]].g += dp[ver[i]]; } chkmin(dp[u], a[u]); } void work(int u, LL v) { a[u] += v; val[dfn[u]].f += v; while (u) { LL tmp = query(1, 1, n, dfn[top[u]], butt[top[u]]).f; modify(1, 1, n, dfn[u]); LL y = query(1, 1, n, dfn[top[u]], butt[top[u]]).f; u = fa[top[u]]; val[dfn[u]].g += y - tmp; } } int main() { n = read(); for (int i = 1; i <= n; ++i) a[i] = read(); for (int i = 1; i < n; ++i) { int u = read(), v = read(); link(u, v); link(v, u); } dfs1(1, 0), dfs2(1, 1); for (int i = 1; i <= n; ++i) val[dfn[i]].f = a[i]; build(1, 1, n); int m = read(); while (m--) { char op[2]; int x; LL y; scanf("%s %d", op, &x); if (op[0] == 'Q') { printf("%lld\n", query(1, 1, n, dfn[x], butt[top[x]]).f); } else { scanf("%lld", &y); work(x, y); } } return 0; }