LibreOJ 2955 「NOIP2018」保卫王国 发表于 2019.11.12 | 分类于 题解 | 16 考虑一个朴素的树形 DP: 设 fu,0/1 表示选 / 不选 u 这个点的情况下,以 u 为根子树内的最小点覆盖。 有转移 fu,0=∑(u,v)∈Efv,1fu,1=au+∑(u,v)∈Emin(fv,0,fv,1) 对轻重儿子分类讨论,设 gu,0/1 表示不考虑重儿子贡献的 fu。 则 fu,0=gu,0+fsonu,1fu,1=gu,1+min(fsonu,0,fsonu,1) 定义 ⊗ 为把乘法换成加法,把加法换成去 min 的矩乘。 把转移写成 ⊗ 的形式: [∞gu,0gu,1gu,1]⊗[fsonu,0fsonu,1]=[fu,0fu,1] 树剖维护即可。 代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121#include <cstdio>#include <algorithm>#define ls (p << 1)#define rs (ls | 1)using namespace std;const int N = 1e5;int n,m;int a[N + 5];int to[N * 2 + 5],pre[N * 2 + 5],first[N + 5];inline void add(int u,int v){ static int tot = 0; to[++tot] = v,pre[tot] = first[u],first[u] = tot;}struct Matrix{ long long a[2][2]; inline Matrix() { a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0x3f3f3f3f3f3f3f3f; } inline Matrix(int) { a[0][0] = a[1][1] = 0,a[0][1] = a[1][0] = 0x3f3f3f3f3f3f3f3f; } inline Matrix(long long _0,long long _1) { a[0][0] = 0x3f3f3f3f3f3f3f3f,a[0][1] = _0,a[1][0] = a[1][1] = _1; } inline Matrix operator*(const Matrix &o) { Matrix ret; for(register int i = 0;i < 2;++i) for(register int j = 0;j < 2;++j) for(register int k = 0;k < 2;++k) ret.a[i][j] = min(ret.a[i][j],a[i][k] + o.a[k][j]); return ret; }} seg[(N << 2) + 10];void insert(int x,Matrix k,int p,int tl,int tr){ if(tl == tr) { seg[p] = k; return ; } int mid = tl + tr >> 1; x <= mid ? insert(x,k,ls,tl,mid) : insert(x,k,rs,mid + 1,tr); seg[p] = seg[ls] * seg[rs];}Matrix query(int l,int r,int p,int tl,int tr){ if(l <= tl && tr <= r) return seg[p]; int mid = tl + tr >> 1; Matrix ret(1); l <= mid && (ret = ret * query(l,r,ls,tl,mid),1); r > mid && (ret = ret * query(l,r,rs,mid + 1,tr),1); return ret;}int fa[N + 5],sz[N + 5],son[N + 5],top[N + 5],id[N + 5],ed[N + 5];long long f[N + 5][2],g[N + 5][2];void dfs1(int p){ sz[p] = 1,f[p][1] = a[p]; for(register int i = first[p];i;i = pre[i]) if(to[i] ^ fa[p]) { fa[to[i]] = p,dfs1(to[i]),sz[p] += sz[to[i]]; if(!son[p] || sz[to[i]] > sz[son[p]]) son[p] = to[i]; f[p][0] += f[to[i]][1],f[p][1] += min(f[to[i]][0],f[to[i]][1]); }}void dfs2(int p){ static int tot = 0; id[p] = ++tot,g[p][1] = a[p]; if(son[p]) top[son[p]] = top[p],dfs2(son[p]); else ed[top[p]] = id[p]; for(register int i = first[p];i;i = pre[i]) if(!id[to[i]]) top[to[i]] = to[i],g[p][0] += f[to[i]][1],g[p][1] += min(f[to[i]][0],f[to[i]][1]),dfs2(to[i]);}void update(int x){ for(;x;x = fa[x]) { insert(id[x],Matrix(g[x][0],g[x][1]),1,1,n),x = top[x]; Matrix cur = query(id[x],ed[x],1,1,n); 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 main(){ freopen("defense.in","r",stdin),freopen("defense.out","w",stdout); scanf("%d%d%*s",&n,&m); for(register int i = 1;i <= n;++i) scanf("%d",a + i); int u,v; for(register int i = 1;i < n;++i) scanf("%d%d",&u,&v),add(u,v),add(v,u); top[1] = 1,dfs1(1),dfs2(1); for(register int i = 1;i <= n;++i) insert(id[i],Matrix(g[i][0],g[i][1]),1,1,n); int x,y; for(long long _0,_1;m;--m) { scanf("%d%d%d%d",&u,&x,&v,&y),x ^= 1,y ^= 1; _0 = g[u][x],_1 = g[v][y]; g[u][x] = 0x3f3f3f3f3f3f3f3f,update(u); g[v][y] = 0x3f3f3f3f3f3f3f3f,update(v); printf("%lld\n",min(f[1][0],f[1][1]) < 0x3f3f3f3f3f3f3f3f ? min(f[1][0],f[1][1]) : -1LL); g[u][x] = _0,update(u); g[v][y] = _1,update(v); }} 本文作者: Alpha1022 本文链接: https://www.alpha1022.me/articles/loj-2955.htm 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处!