首先正着搜是错的。。因为搜索的顺序会影响结果。。
那么就把所有点按法术攻击的大小都加入小根堆,每次取出最小的,那么解决它就只需要用法术攻击了。因为肯定存在解决它的儿子用法术攻击的情况,而且需要的花费比解决它的法术攻击还大,那必然用一次法术攻击解决它,不过存在当它没有儿子时,就把法术攻击和普通攻击取个min就对了。
这样就相当于在一个DAG上跑dijkstra了,当它们的父亲度数也为 \(0\) 了就可以更新。
复杂度 \(O(n \log n)\)
#include <bits/stdc++.h>
#define ll long long
namespace IO {
const int MAXSIZE = 1 << 20;
char buf[MAXSIZE], *p1, *p2;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin), p1 == p2) ? EOF : *p1++)
void read() {}
template<typename T, typename ... T2>
inline void read(T &x, T2 &... oth) {
x = 0; T f = 1; char ch = gc();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = gc(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = gc(); }
x *= f;
read(oth...);
}
}
const int N = 2e5 + 7;
const int M = 1e6 + 7;
int head1[N], head2[N], cnt = 1, n, deg[N];
ll dis[N], a[N];
struct E {
int v, ne;
} e[M << 1];
void add(int u, int v, int *head) {
e[++cnt].v = v; e[cnt].ne = head[u]; head[u] = cnt;
}
struct Node {
int u;
ll d;
Node(int _u = 0, ll _d = 0): u(_u), d(_d) {}
bool operator < (const Node &p) const {
return d > p.d;
}
};
std::priority_queue<Node> que;
bool done[N];
int main() {
IO::read(n);
for (int i = 1, x; i <= n; i++) {
IO::read(a[i], dis[i], deg[i]);
for (int j = 1; j <= deg[i]; j++) {
int x;
IO::read(x);
add(i, x, head1);
add(x, i, head2);
}
if (!deg[i]) dis[i] = std::min(dis[i], a[i]);
que.push(Node(i, dis[i]));
}
while (!que.empty()) {
Node p = que.top(); que.pop();
int u = p.u;
if (u == 1) break;
if (done[u]) continue;
done[u] = 1;
for (int i = head2[u]; i; i = e[i].ne) {
int fa = e[i].v;
deg[fa]--;
if (!deg[fa] && !done[fa]) {
ll temp = a[fa];
for (int j = head1[fa]; j; j = e[j].ne)
temp += dis[e[j].v];
if (temp < dis[fa]) {
dis[fa] = temp;
que.push(Node(fa, dis[fa]));
}
}
}
}
printf("%lld\n", dis[1]);
return 0;
}