Luogu5024 保卫王国
https://www.luogu.com.cn/problem/P5024
动态DP
\(f_{u,0}\)表示以\(u\)为根的子树中,\(u\)不取的最小开销
\(f_{u,1}\)表示以\(u\)为根的子树中,\(u\)必取的最小开销
\(g_{u,0}\)表示以\(u\)为根的子树中,不取重儿子,且\(u\)不取的最小开销
\(g_{u,1}\)表示以\(u\)为根的子树中,不取重儿子,且\(u\)必取的最小开销
设\(u\)的重儿子为\(w\)
\[f_{u,0}=g_{u,0}+f_{w,1}\\
f_{u,1}=g_{u,1}+\min(f_{w,0},f_{w,1})
\]
转化方程
\[f_{u,0}=\min(+\infty+f_{w,0},g_{u,0}+f_{w,1})\\
f_{u,1}=\min(g_{u,1}+f_{w,0},g_{u,1}+f_{w,1})
\]
重定义矩阵乘法运算
\[C_{i,j}=\min A_{i,k}+B_{k,j}
\]
转化为矩阵乘法
\[\begin{vmatrix}
+\infty & g_{u,0}\\
g_{u,1} & g_{u,1}
\end{vmatrix}
\times
\begin{vmatrix}
f_{w,0} \\
f_{w,1}
\end{vmatrix}
=
\begin{vmatrix}
f_{u,0} \\
f_{u,1}
\end{vmatrix}
\]
初始化叶子节点
\[\begin{vmatrix}
0 \\
Val_i
\end{vmatrix}
\]
转化成\(2\times 2\)矩阵
\[\begin{vmatrix}
0 & +\infty \\
Val_i & +\infty
\end{vmatrix}
\]
基本结束
注意:节点\(a,b\)的\(g\)值也需要修改后再修改全局平衡二叉树
\(Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100005
#define INF 10000000000007
#define ll long long
#define fa(x) F[x]
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
using namespace std;
int n,m,a,b,x,y,tot,rt,frt,val[N],fr[N],nxt[N << 1],d[N << 1];
int F[N],sz[N],son[N];
int q[N],qz[N];
int ch[N][2];
ll rc,rd,f[N][2],g[N][2];
char ty[5];
struct mat
{
ll w[2][2];
void setmat(ll a=0,ll b=INF,ll c=INF,ll d=0)
{
w[0][0]=a,w[0][1]=b;
w[1][0]=c,w[1][1]=d;
}
mat operator * (mat b)
{
mat c;
c.w[0][0]=min(w[0][0]+b.w[0][0],w[0][1]+b.w[1][0]);
c.w[0][1]=min(w[0][0]+b.w[0][1],w[0][1]+b.w[1][1]);
c.w[1][0]=min(w[1][0]+b.w[0][0],w[1][1]+b.w[1][0]);
c.w[1][1]=min(w[1][0]+b.w[0][1],w[1][1]+b.w[1][1]);
return c;
}
ll mn()
{
return min(w[0][0],w[1][0]);
}
}z[N],s[N],ra,rb;
void add(int x,int y)
{
tot++;
d[tot]=y;
nxt[tot]=fr[x];
fr[x]=tot;
}
void dfs1(int u)
{
int mx=-1;
sz[u]=1;
for (int i=fr[u];i;i=nxt[i])
{
int v=d[i];
if (v==F[u])
continue;
F[v]=u;
dfs1(v);
sz[u]+=sz[v];
if (sz[v]>mx)
{
mx=sz[v];
son[u]=v;
}
}
}
void update(int x)
{
s[x]=s[ls(x)]*z[x]*s[rs(x)];
}
int build(int l,int r)
{
if (l>r)
return 0;
int hs=(qz[r]-qz[l-1]) >> 1,o;
int L=l,R=r;
while (L<=R)
{
int mid=(L+R) >> 1;
if (qz[mid]-qz[l-1]>=hs)
{
o=mid;
R=mid-1;
} else
L=mid+1;
}
ls(q[o])=build(l,o-1);
rs(q[o])=build(o+1,r);
update(q[o]);
fa(ls(q[o]))=q[o];
fa(rs(q[o]))=q[o];
return q[o];
}
void dfs2(int u)
{
g[u][0]=0,g[u][1]=val[u];
if (!son[u])
{
f[u][0]=g[u][0],f[u][1]=g[u][1];
z[u].setmat(0,INF,val[u],INF);
} else
{
dfs2(son[u]);
for (int i=fr[u];i;i=nxt[i])
{
int v=d[i];
if (v==F[u] || v==son[u])
continue;
dfs2(v);
g[u][0]+=f[v][1];
g[u][1]+=min(f[v][0],f[v][1]);
}
f[u][0]=g[u][0]+f[son[u]][1];
f[u][1]=g[u][1]+min(f[son[u]][0],f[son[u]][1]);
z[u].setmat(INF,g[u][0],g[u][1],g[u][1]);
}
if (son[F[u]]!=u)
{
frt=F[u];
q[0]=0;
for (int v=u;v;v=son[v])
q[++q[0]]=v,qz[q[0]]=qz[q[0]-1]+sz[v]-sz[son[v]];
rt=build(1,q[0]);
F[rt]=frt;
}
}
bool isrt(int x)
{
return ls(fa(x))!=x && rs(fa(x))!=x;
}
void modify(int x)
{
for (int u=x;u;u=F[u])
if (!isrt(u) || !fa(u))
update(u); else
{
int v=fa(u);
g[v][0]-=s[u].w[1][0];
g[v][1]-=min(s[u].w[0][0],s[u].w[1][0]);
update(u);
g[v][0]+=s[u].w[1][0];
g[v][1]+=min(s[u].w[0][0],s[u].w[1][0]);
z[v].setmat(INF,g[v][0],g[v][1],g[v][1]);
}
}
int main()
{
scanf("%d%d%s",&n,&m,ty);
for (int i=1;i<=n;i++)
scanf("%d",&val[i]);
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs1(1);
z[0].setmat(),s[0].setmat();
dfs2(1);
while (m --> 0)
{
scanf("%d%d%d%d",&a,&x,&b,&y);
ra=z[a];
if (x==0)
rc=g[a][1],g[a][1]=INF; else
rc=g[a][0],g[a][0]=INF;
if (son[a])
{
if (x==0)
z[a].w[1][0]=z[a].w[1][1]=INF; else
z[a].w[0][1]=INF;
} else
{
if (x==0)
z[a].w[1][0]=INF; else
z[a].w[0][0]=INF;
}
modify(a);
rb=z[b];
if (y==0)
rd=g[b][1],g[b][1]=INF; else
rd=g[b][0],g[b][0]=INF;
if (son[b])
{
if (y==0)
z[b].w[1][0]=z[b].w[1][1]=INF; else
z[b].w[0][1]=INF;
} else
{
if (y==0)
z[b].w[1][0]=INF; else
z[b].w[0][0]=INF;
}
modify(b);
printf("%lld\n",(s[rt].mn()<INF)?s[rt].mn():-1);
if (y==0)
g[b][1]=rd; else
g[b][0]=rd;
z[b]=rb;
modify(b);
if (x==0)
g[a][1]=rc; else
g[a][0]=rc;
z[a]=ra;
modify(a);
}
return 0;
}