Address
https://www.lydsy.com/JudgeOnline/problem.php?id=3875
Solution
很容易想到设
f[i]
f
[
i
]
表示彻底杀死第
i
i
个怪兽所需的最小体力值。
可以得出 之间满足:
f[i]=min(Ki,Si+∑怪兽i死亡后会产生怪兽jf[j])
f
[
i
]
=
min
(
K
i
,
S
i
+
∑
怪
兽
i
死
亡
后
会
产
生
怪
兽
j
f
[
j
]
)
考虑如果怪兽 i i 死亡后会产生怪兽 ,那么就连边 <i,j> < i , j > <script type="math/tex" id="MathJax-Element-632"> </script> 。
这个图可能有环,故直接转移行不通。
我们考虑用 SPFA 来实现转移。
首先, f[i] f [ i ] 一定不超过 Ki K i ,故我们先把所有的 f[i] f [ i ] 设为 Ki K i 。
然后把所有的 i i 加入队列。
每一次,取出队头元素 。
进行检查,如果 Si+∑f[j] S i + ∑ f [ j ] 能够更新 f[i] f [ i ] ,那么就把 f[i] f [ i ] 设成 Si+Σf[i] S i + Σ f [ i ] 。
注意到 f[i] f [ i ] 被更新之后,如果存在边 <j,i> < j , i > <script type="math/tex" id="MathJax-Element-644"> </script> ,那么 f[j] f [ j ] 的值也会被更新。
故我们还要把 j j 加入队尾(如果已经在队中就不要加),使得 能够在后面被更新。
最后答案 f[1] f [ 1 ] 。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
#define Egde(u) for (int e = adj2[u], v = go2[e]; e; e = nxt2[e], v = go2[e])
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
inline ll readll() {
ll res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 2e5 + 5, M = 1e6 + 5, L = 15e6 + 5;
int n, R[N], ecnt, nxt[M], adj[N], go[M], ecnt2, nxt2[M],
adj2[N], go2[M], que[L];
ll f[N], S[N], K[N];
bool vis[N];
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
}
void add_edge2(int u, int v) {
nxt2[++ecnt2] = adj2[u]; adj2[u] = ecnt2; go2[ecnt2] = v;
}
ll SPFA() {
int i, H = 0, T = n;
For (i, 1, n) f[que[i] = i] = K[i], vis[i] = 1;
while (H < T) {
int u = que[++H]; vis[u] = 0;
ll sum = S[u];
Edge(u) sum += f[v];
if (sum >= f[u]) continue;
f[u] = sum;
Egde(u) if (!vis[v]) vis[que[++T] = v] = 1;
}
return f[1];
}
int main() {
int i, j, x;
n = read();
For (i, 1, n) {
S[i] = readll(); K[i] = readll(); R[i] = read();
For (j, 1, R[i]) x = read(), add_edge(i, x), add_edge2(x, i);
}
cout << SPFA() << endl;
return 0;
}