noip2018 保卫王国
动态维护树上最小点覆盖
$n \leq 100000$
sol:动态 dp,请
先写一个树上的 dp
$f_{(x,0)} = \sum f_{(to,1)}$
$f_{(x,1)} = v_x + \sum f_{(to,0)}$
首先考虑链上的情形
链上的转移方程非常的清真,它是
$f_{(x,0)} = f_{(to,1)}$
$f_{(x,1)} = v_x + f_{(to,0)}$
$to$ 就是 $x$ 左边的点
这个方程是一个广义的常系数线性递推(把 min 看成线性),可以用一个广义的矩阵来维护
维护一个矩阵 $ \left[ \begin{matrix} 0 & \infty \\ v_x & v_x \end{matrix} \right]$
则 $ \left[ \begin{matrix} 0 & \infty \\ v_x & v_x \end{matrix} \right] \times \left[ \begin{matrix} f_{(x-1,0)} \\ f_{(x-1,1)} \end{matrix} \right] = \left[ \begin{matrix} f_{(x,0)} \\ f_{(x,1)} \end{matrix} \right]$
于是上树的情况就是:在重链上维护这个转移式,因为一个点到根最多经过 logn 条重链,所以复杂度是 $O(nlog^2n)$
上树的时候会发现矩阵有一些变化,因为还要维护轻链上的转移,我们可以设 $A = \sum\limits_{v \in light_x} f_{(v,1)},B = v_x + \sum\limits_{v \in light_x} min(f_{(v,1)},f_{(v,0)})$
则每个点的矩阵是
$ \left[ \begin{matrix} A & \infty \\ B & B \end{matrix} \right]$
维护这个的同时维护一下 $g$ 数组表示这个点所有轻儿子的信息即可
写了好几次动态 dp 了,每次都重学
这是最后一次(flag
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define LL long long #define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i) #define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i) using namespace std; inline int read() { int x = 0,f = 1; char ch = getchar(); for(; !isdigit(ch); ch = getchar())if(ch == '-') f = -f; for(; isdigit(ch); ch = getchar())x = 10 * x + ch - '0'; return x * f; } const LL oo = 1e10, maxn = 5e5 + 10; /* A inf B B A = sigma (light, 1) B = val + sigma(light, min(0, 1)) A inf hv (0) B B hv (1) */ struct Matrix { LL a[2][2]; Matrix(){ rep(i, 0, 1) rep(j, 0, 1) a[i][j] = oo; } Matrix(LL x, LL y){ a[0][1] = x, a[1][0] = a[1][1] = y, a[0][0] = oo; } Matrix operator * (const Matrix &b) const { Matrix c; rep(i, 0, 1) rep(j, 0, 1) rep(k, 0, 1) c.a[i][j] = min(c.a[i][j], a[i][k] + b.a[k][j]); return c; } }; Matrix seg[maxn << 2], Mod; #define ls (x << 1) #define rs ((x << 1) | 1) inline void update(int x, int l, int r, int pos, Matrix Mod) { //cout << x << endl; if(l == r) { seg[x] = Mod; return; } int mid = (l + r) >> 1; if(pos <= mid) update(ls, l, mid, pos, Mod); else update(rs, mid+1, r, pos, Mod); seg[x] = seg[ls] * seg[rs]; } inline Matrix query(int x, int l, int r, int L, int R) { if(L <= l && r <= R) return seg[x]; int mid = (l + r) >> 1; Matrix ret; ret.a[0][1] = ret.a[1][0] = oo; ret.a[0][0] = ret.a[1][1] = 0; if(L <= mid) ret = ret * query(ls, l, mid, L, R); if(R > mid) ret = ret * query(rs, mid+1, r, L, R); return ret; } int n, m, a[maxn]; LL f[maxn][2], g[maxn][2]; vector<int> G[maxn]; int fa[maxn], mxs[maxn], bl[maxn], pos[maxn], size[maxn], bot[maxn], dfn; inline void dfs1(int x) { size[x] = 1; f[x][1] = a[x]; for(auto to : G[x]) { if(to == fa[x]) continue; fa[to] = x; dfs1(to); size[x] += size[to]; if(!mxs[x] || size[to] > size[mxs[x]]) mxs[x] = to; f[x][0] += f[to][1]; f[x][1] += min(f[to][0], f[to][1]); } //cout << x << " : " << mxs[x] << endl; } inline void dfs2(int x, int col) { bl[x] = col; pos[x] = ++dfn; g[x][1] = a[x]; //cout << pos[x] << " " << bl[x] << endl; if(!mxs[x]) { update(1, 1, n, pos[x], Matrix(g[x][0], g[x][1])); bot[col] = dfn; return; } dfs2(mxs[x], col); for(auto to : G[x]) if(to != mxs[x] && to != fa[x]) { g[x][0] += f[to][1]; g[x][1] += min(f[to][1], f[to][0]); dfs2(to, to); } update(1, 1, n, pos[x], Matrix(g[x][0], g[x][1])); } inline LL Modify(int x) { update(1, 1, n, pos[x], Matrix(g[x][0], g[x][1])); x = bl[x]; while(x > 1) { Matrix cur = query(1, 1, n, pos[x], bot[x]); g[fa[x]][0] -= f[x][1]; g[fa[x]][1] -= min(f[x][0], f[x][1]); f[x][0] = cur.a[0][1], f[x][1] = cur.a[1][1]; g[fa[x]][0] += f[x][1]; g[fa[x]][1] += min(f[x][0], f[x][1]); int cp = fa[x]; update(1, 1, n, pos[cp], Matrix(g[cp][0], g[cp][1])); x = bl[fa[x]]; } // cout << bot[1] << endl; Matrix ans = query(1, 1, n, 1, bot[1]); // cout << "COMP" << endl; return min(ans.a[0][1], ans.a[1][1]); } int main() { //freopen("defense.in","r",stdin); //freopen("defense.out","w",stdout); n = read(), m = read(); scanf("%*s"); rep(i, 1, n) a[i] = read(); rep(i, 2, n) { int u = read(), v = read(); G[u].push_back(v); G[v].push_back(u); } dfs1(1); dfs2(1, 1); while(m--) { int a = read(), x = 1 ^ read(), b = read(), y = 1 ^ read(); LL tmp1 = g[a][x], tmp2 = g[b][y]; g[a][x] = oo, Modify(a); g[b][y] = oo; LL ans = Modify(b); if(ans >= oo) cout << -1 << '\n'; else cout << ans << '\n'; g[a][x] = tmp1, Modify(a); g[b][y] = tmp2, Modify(b); } }