给出一张 $n$ 个点 $m$ 条边的无向图,有$k$ 个关键点。需要给所有无向边定向,如果第 $i$ 条边保留双向,要花费$w_i$的代价。我们称定向后的图上一个点是饱和的,当且仅当所有关键点都能到达它。此时这个点能够有 $c_i$
的收益。请对于每个$i = 1, 2, \ldots, n$ 回答,强制选择 $i$ 号点为饱和点时,收益减代价的最大值。
如果出现了$双连通分量$,那么就可定向成强连通分量,就一定可以两两互通,就不需要考虑。
全部缩点之后,就变成了树。
考虑树上如果进行,并且显然这是个换根$dp$。
$dp[x]$表示以 $x$ 为根节点的子树里,保证 $x$ 是饱和的情况下最小的代价。
换根$dp$
代码
```c++
include
using namespace std;
typedef long long ll;
define pii pair
define mk make_pair
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < ‘0’ || c > ‘9’)
{
if (c == ‘-‘)
f = -1;
c = getchar();
}
while (c >= ‘0’ && c <= ‘9’)
x = (x << 1) + (x << 3) + c - ‘0’, c = getchar();
return x * f;
}
ll sp[N], c[N], w[N], flag[N];
namespace tarjan
{
vector
int dfn[N], low[N], gcnt, ln, fa[N];
stack
void tarjan(int x, int f)
{
dfn[x] = low[x] = ++gcnt;
s.push(x);
for (int i = 0; i < g[x].size(); i++)
{
int to = g[x][i];
if (f == to)
continue;
if (!dfn[to])
{
tarjan(to, x);
low[x] = min(low[x], low[to]);
}
else
low[x] = min(low[x], dfn[to]);
}
if (dfn[x] == low[x])
{
++ln;
while (1)
{
int cur = s.top();
s.pop();
fa[cur] = ln;
w[ln] += c[cur];
flag[ln] |= sp[cur];
if (cur == x)
break;
}
}
}
} // namespace tarjan
struct Edge
{
int u, v;
int w;
} e[N];
vector
ll dp[N];
void dfs1(int x, int fa)
{
for (pii now : g[x])
{
int to = now.first;
if (fa == to)
continue;
dfs1(to, x);
flag[x] |= flag[to];
}
}
void dfs2(int x, int fa)
{
dp[x] = w[x];
for (pii now : g[x])
{
int to = now.first;
if (fa == to)
continue;
dfs2(to, x);
if (flag[to] == 0)
dp[x] += dp[to];
else if (dp[to] - now.second > 0)
dp[x] += dp[to] - now.second;
}
}
void dfs3(int x, int fa)
{
for (pii now : g[x])
{
int to = now.first, w = now.second;
if (fa == to)
continue;
if (flag[to] == 1)
dp[to] += max(0ll, dp[x] - max(0ll, dp[to] - w) - w);
else
dp[to] = dp[x];
dfs3(to, x);
}
}
int main()
{
int n = read(), m = read(), k = read();
for (int i = 1; i <= k; i++)
{
int x = read();
sp[x] = 1;
}
for (int i = 1; i <= n; i++)
c[i] = read();
for (int i = 1; i <= m; i++)
e[i].w = read();
for (int i = 1; i <= m; i++)
{
e[i].u = read(), e[i].v = read();
tarjan::g[e[i].u].push_back(e[i].v);
tarjan::g[e[i].v].push_back(e[i].u);
}
tarjan::tarjan(1, 0);
for (int i = 1; i <= m; i++)
{
int u = tarjan::fa[e[i].u], v = tarjan::fa[e[i].v], w = e[i].w;
if (u != v)
{
g[u].push_back(mk(v, w));
g[v].push_back(mk(u, w));
}
}
int rt = 1;
for (int i = 1; i <= tarjan::ln; i++)
if (flag[i])
rt = i;
dfs1(rt, 0);
dfs2(rt, 0);
dfs3(rt, 0);
for (int i = 1; i <= n; i++)
printf("%lld ", dp[tarjan::fa[i]]);
}