七海ノ心象素描

所有的为时已晚都是恰逢其时

LOJ#2955 保卫王国 题解

Solution

如月七海
如月七海 局外人
2023年09月07日
预计阅读 6 分钟
1193 字

部分分

先考虑暴力怎么打。

规定原树为 TT,以 xx 为根的子树为 T(x)T(x)

f(x,0/1)f(x,0/1) 为考虑 T(x)T(x),其中 xx 选或不选的最小权点覆盖,设 g(x,0/1)g(x,0/1) 为考虑 TT(x)T-T(x),其中 xx 选或不选的最小权点覆盖。有转移

f(x,0)=yson(x)f(y,1)f(x,0) = \sum_{y \in son(x)} f(y,1) f(y,1)=yson(x)min(f(y,0),f(y,1))f(y,1) = \sum_{y \in son(x)} \min\Big(f(y,0),f(y,1)\Big) g(y,0)=g(x,1)+f(x,1)min(f(y,0),f(y,1))g(y,0) = g(x,1) + f(x,1) - \min\Big(f(y,0),f(y,1)\Big) g(y,1)=min(g(x,0)+f(x,0)f(y,1),g(y,0))g(y,1) = \min \Big( g(x,0)+f(x,0)-f(y,1),g(y,0) \Big)

预处理 ffgg,复杂度是 O(n)O(n) 的。

z=LCA(x,y)z = \text{LCA}(x,y),对于每个询问,我们暴力修改 f(x)f(x)f(y)f(y),然后求出 f(z)f(z) 即可。

这样可以通过前 1111 个测试点。

对于链的情况,我们直接预处理前缀与后缀最小权点覆盖,然后对 [x,y][x,y] 做矩阵加速的最小权点覆盖即可。

然后就通过前 1717 个点了。

正解

承接上文,我不会动态 DP。

fa(x,i)fa(x,i)xx2i2^i 级祖先,h(x,i,a,b)h(x,i,a,b) 为从 xxfa(x,i)fa(x,i),其中 xx 的驻军状态是 aafa(x,i)fa(x,i) 的驻军状态是 bb,这条链的最小代价。

这个的预处理就比上一题简单不少了。

// int h[N][17][2][2]
auto H=h[y][0];
H[1][0]=f[x][0]-f[y][1];
H[1][1]=H[0][1]=f[x][1]-min(f[y][0],f[y][1]);
// 然后倍增一下

根据个人习惯把询问改为 (x,a,y,b)(x,a,y,b),表示强制令节点 xx 的状态为 aayy 的状态为 bb

钦定 dep(x)dep(y)\text{dep}(x) \ge \text{dep}(y)z=LCA(x,y)z = \text{LCA}(x,y)

如果 z=yz=y,那么直接倍增出 (x,y)(x,y) 的最小代价,加上 f(x,a)f(x,a)g(y,b)g(y,b)

否则拆成 (x,prex(z))\Big(x,pre_x(z)\Big)(y,prey(z))\Big(y,pre_y(z)\Big) 两条链,分别倍增求出,再拼起来。

其中 prex(z)pre_x(z) 表示 xx 的一个祖先,满足它是 yy 的一个子节点。

prex(z)pre_x(z) 的过程可以放进倍增求 LCA\text{LCA} 中,很方便。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
int a=0, f=1; char c=getchar();
while(!isdigit(c)) {
if(c=='-') f=-1;
c=getchar();
}
while(isdigit(c)) a=a*10+c-'0', c=getchar();
return a*f;
}
const int N=1e5+5, inf=0x0f0f0f0f0f0f0f0f;
int n, m, lim, c[N], dep[N];
int f[N][2], g[N][2];
int fa[N][17], h[N][17][2][2];
vector<int> p[N];
char s[5];
void dfs1(int x,int fr)
{
dep[x]=dep[fr]+1;
fa[x][0]=fr;
for(int i=1;(1<<i)<=dep[x];++i) fa[x][i]=fa[fa[x][i-1]][i-1];
f[x][0]=0, f[x][1]=c[x];
for(auto y:p[x]) if(y!=fr) {
dfs1(y,x);
f[x][0]+=f[y][1];
f[x][1]+=min(f[y][0],f[y][1]);
}
}
void dfs2(int x,int fr) {
for(auto y:p[x]) if(y!=fr) {
g[y][0]=g[x][1]+f[x][1]-min(f[y][0],f[y][1]);
g[y][1]=min(g[x][0]+f[x][0]-f[y][1],g[y][0]);
auto H=h[y][0];
H[1][0]=f[x][0]-f[y][1];
H[1][1]=H[0][1]=f[x][1]-min(f[y][0],f[y][1]);
for(int i=1;(1<<i)<=dep[y];++i) rep(a,0,1) rep(b,0,1) rep(c,0,1) {
h[y][i][a][c]=min(h[y][i][a][c],h[y][i-1][a][b]+h[fa[y][i-1]][i-1][b][c]);
}
dfs2(y,x);
}
}
vector<int> calc(int x,int a,int y) {
vector<int> res(2);
res[a]=0;
res[a^1]=inf;
for(int i=lim;~i;--i) if(fa[x][i]&&dep[fa[x][i]]>=dep[y]) {
vector<int> t(2,inf);
rep(a,0,1) rep(b,0,1) t[b]=min(t[b],res[a]+h[x][i][a][b]);
x=fa[x][i], res=t;
}
return res;
}
int solve(int x,int a,int y,int b) {
int tx=x, ty=y;
for(int i=lim;~i;--i) if(fa[x][i]&&dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) {
return calc(tx,a,y)[b]+f[tx][a]+g[y][b];
}
for(int i=lim;~i;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
int z=fa[x][0];
auto F=calc(tx,a,x), G=calc(ty,b,y);
int res0=F[1]+G[1]+(f[z][0]-f[x][1]-f[y][1])+g[z][0];
int res1=min(F[0],F[1])+min(G[0],G[1])+(f[z][1]-min(f[x][0],f[x][1])-min(f[y][0],f[y][1]))+g[z][1];
// 两种情况为z是否驻军
return min(res0,res1)+f[tx][a]+f[ty][b];
}
signed main() {
freopen("defense.in","r",stdin);
freopen("defense.out","w",stdout);
n=read(), m=read();
scanf("%s",s);
rep(i,1,n) c[i]=read();
rep(i,2,n) {
int x=read(), y=read();
p[x].pb(y), p[y].pb(x);
}
while(1<<(lim+1)<=n) ++lim;
SET(h,0x0f);
dfs1(1,0);
dfs2(1,0);
while(m--) {
int x=read(), a=read(), y=read(), b=read();
if(dep[x]<dep[y]) swap(x,y), swap(a,b);
if(!a&&!b&&fa[x][0]==y) puts("-1");
else printf("%lld\n",solve(x,a,y,b));
}
return 0;
}

觉得这篇文章怎么样?

点个赞,让更多人看到!

分享这篇文章

知识因分享而增值

分类

题解

标签

树论
树上倍增
DP

版权声明:本文作者为 如月七海,首发于nanami7.top

遵循 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

评论区

本评论区由 EveSunMaple自主开发