LOJ#2955 保卫王国 题解
Solution
如月七海 局外人
2023年09月07日
预计阅读 6 分钟
1193 字
部分分
先考虑暴力怎么打。
规定原树为 ,以 为根的子树为 。
设 为考虑 ,其中 选或不选的最小权点覆盖,设 为考虑 ,其中 选或不选的最小权点覆盖。有转移
预处理 与 ,复杂度是 的。
设 ,对于每个询问,我们暴力修改 与 ,然后求出 即可。
这样可以通过前 个测试点。
对于链的情况,我们直接预处理前缀与后缀最小权点覆盖,然后对 做矩阵加速的最小权点覆盖即可。
然后就通过前 个点了。
正解
承接上文,我不会动态 DP。
设 为 的 级祖先, 为从 到 ,其中 的驻军状态是 , 的驻军状态是 ,这条链的最小代价。
这个的预处理就比上一题简单不少了。
// 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]);// 然后倍增一下根据个人习惯把询问改为 ,表示强制令节点 的状态为 , 的状态为 。
钦定 ,。
如果 ,那么直接倍增出 的最小代价,加上 与 。
否则拆成 与 两条链,分别倍增求出,再拼起来。
其中 表示 的一个祖先,满足它是 的一个子节点。
求 的过程可以放进倍增求 中,很方便。
#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;}觉得这篇文章怎么样?
点个赞,让更多人看到!

评论区