洛谷 P5024 保卫王国
Z国有n座城市,n−1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达。
Z国的国防部长小Z要在城市中驻扎军队。驻扎军队需要满足如下几个条件:
- 一座城市可以驻扎一支军队,也可以不驻扎军队。
- 由道路直接连接的两座城市中至少要有一座城市驻扎军队。
- 在城市里驻扎军队会产生花费,在编号为i的城市中驻扎军队的花费是\(p_i\)。
小 Z 很快就规划出了一种驻扎军队的方案,使总花费最小。但是国王又给小Z提出了m个要求,每个要求规定了其中两座城市是否驻扎军队。小Z需要针对每个要求逐一给出回答。具体而言,如果国王提出的第j个要求能够满足上述驻扎条件(不需要考虑第j个要求之外的其它要求),则需要给出在此要求前提下驻扎军队的最小开销。如果 国王提出的第j个要求无法满足,则需要输出-1\((1\le j\le m)\)。现在请你来帮助小Z。
真是一道noip的毒瘤题
最小权覆盖集=点权和-最大权独立集
每次询问选或不选相当于给每个点赋无穷小或无穷大,然后就可以ddp了,好了做完了
但是这个题没有修改,所以我们考虑倍增
先预处理出来\(f_{u,0/1}\)表示u不选或选时以其为根子树的答案,\(g_{u,0/1}\)表示u不选或选时整棵树去掉以u为根的子树的答案
这两个都可以树上dp出来
然后我们维护一个倍增数组\(dp_{u,i,0/1,0/1}\)表示u不选或选和u的\(2^i\)祖先不选或选时,以u的\(2^i\)祖先为根的子树去掉以u为根的子树的答案
这个也可以顺着树上dp的思路倍增出来
然后根据倍增往上跳就可以了,顺便统计一下答案
当然,只有在a,b都不能驻扎军队并且a和b有边相连的情况下才会无解
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#define LL long long
const int N = 1e5;
const LL INF = 1e15;
using namespace std;
int n,m,p[N + 5];
int dep[N + 5],fa[N + 5][25];
LL dp[N + 5][25][2][2],f[N + 5][2],g[N + 5][2];
char ch[5];
vector <int> d[N + 5];
void dfs1(int u,int F)
{
vector <int>::iterator it;
fa[u][0] = F;
f[u][1] = p[u];
dep[u] = dep[F] + 1;
for (it = d[u].begin();it != d[u].end();it++)
{
int v = (*it);
if (v == F)
continue;
dfs1(v,u);
f[u][1] += min(f[v][0],f[v][1]);
f[u][0] += f[v][1];
}
}
void dfs2(int u,int F)
{
vector <int>::iterator it;
for (it = d[u].begin();it != d[u].end();it++)
{
int v = (*it);
if (v == F)
continue;
g[v][0] = g[u][1] + f[u][1] - min(f[v][1],f[v][0]);
g[v][1] = min(g[u][0] + f[u][0] - f[v][1],g[v][0]);
dfs2(v,u);
}
}
LL solve(int a,int x,int b,int y)
{
if (dep[a] < dep[b])
swap(a,b),swap(x,y);
LL ta[2] = {INF,INF},tb[2] = {INF,INF},na[2],nb[2];
ta[x] = f[a][x];
tb[y] = f[b][y];
for (int i = 18;i >= 0;i--)
if (dep[fa[a][i]] >= dep[b])
{
na[0] = na[1] = INF;
for (int j = 0;j <= 1;j++)
for (int k = 0;k <= 1;k++)
na[j] = min(na[j],ta[k] + dp[a][i][k][j]);
ta[1] = na[1];
ta[0] = na[0];
a = fa[a][i];
}
if (a == b)
return ta[y] + g[b][y];
for (int i = 18;i >= 0;i--)
if (fa[a][i] != fa[b][i])
{
na[0] = na[1] = nb[0] = nb[1] = INF;
for (int j = 0;j <= 1;j++)
for (int k = 0;k <= 1;k++)
{
na[j] = min(na[j],ta[k] + dp[a][i][k][j]);
nb[j] = min(nb[j],tb[k] + dp[b][i][k][j]);
}
ta[1] = na[1];
ta[0] = na[0];
tb[1] = nb[1];
tb[0] = nb[0];
a = fa[a][i];
b = fa[b][i];
}
int lca = fa[a][0];
return min(f[lca][0] - f[a][1] - f[b][1] + ta[1] + tb[1] + g[lca][0],f[lca][1] - min(f[a][0],f[a][1]) - min(f[b][0],f[b][1]) + min(ta[0],ta[1]) + min(tb[0],tb[1]) + g[lca][1]);
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",ch + 1);
for (int i = 1;i <= n;i++)
scanf("%d",&p[i]);
int u,v;
for (int i = 1;i < n;i++)
{
scanf("%d%d",&u,&v);
d[u].push_back(v);
d[v].push_back(u);
}
for (int i = 1;i <= n;i++)
sort(d[i].begin(),d[i].end());
dfs1(1,0);
dfs2(1,0);
for (int i = 1;i <= n;i++)
{
dp[i][0][0][0] = INF;
dp[i][0][1][0] = f[fa[i][0]][0] - f[i][1];
dp[i][0][1][1] = f[fa[i][0]][1] - min(f[i][0],f[i][1]);
dp[i][0][0][1] = f[fa[i][0]][1] - min(f[i][0],f[i][1]);
}
for (int i = 1;i <= 18;i++)
for (int j = 1;j <= n;j++)
{
fa[j][i] = fa[fa[j][i - 1]][i - 1];
for (int x = 0;x <= 1;x++)
for (int y = 0;y <= 1;y++)
{
dp[j][i][x][y] = INF;
for (int z = 0;z <= 1;z++)
dp[j][i][x][y] = min(dp[j][i][x][y],dp[j][i - 1][x][z] + dp[fa[j][i - 1]][i - 1][z][y]);
}
}
int a,x,b,y;
for (int i = 1;i <= m;i++)
{
scanf("%d%d%d%d",&a,&x,&b,&y);
if (x == 0 && y == 0 && *lower_bound(d[a].begin(),d[a].end(),b) == b)
printf("-1\n");
else
printf("%lld\n",solve(a,x,b,y));
}
return 0;
}