题目大意
现在有一个游戏,一共有两种攻击方式,一种是普通攻击,一种是法术攻击。两种攻击方式都会消耗一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。
现在一共有
N
种不同的怪兽,每只怪兽有几个参数
N≤2∗105
∑Rii=1=106
Ki,Si≤5∗1014
解题思路
我们可以考虑贪心的去杀怪兽,我们设
Fi
表示杀掉第
i
只怪兽的最小花费,一个显然的转移就是
考虑
Ki
最小的点,这个怪兽肯定是被法术杀死的。那么这个怪兽的
F
值就是确定的。那么只能变成这个怪兽的怪兽就可以转移了。这就很像拓扑序时的操作了。每次选一个
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
const int MAXN = 2e5 + 5, MAXM = 1e6 + 5;
int tot, Last[MAXN], Go[MAXM], Next[MAXM];
map<int,int> Map[MAXN];
int N, Num[MAXN], Ord[MAXN];
LL S[MAXN], K[MAXN], F[MAXN];
int D[MAXN], l, r;
bool Flag[MAXN];
bool Cmp(int A, int B) {
return K[A] < K[B];
}
void Link(int u, int v) {
Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v;
}
int main() {
freopen("knight.in", "r", stdin), freopen("knight.out", "w", stdout);
scanf("%d", &N);
for (int i = 1; i <= N; i ++) {
scanf("%lld%lld%d", &S[i], &K[i], &Num[i]);
S[i] = min(K[i], S[i]);
F[i] = S[i];
for (int j = 1; j <= Num[i]; j ++) {
int Now;
scanf("%d", &Now);
Map[i][Now] ++;
Link(Now, i);
}
Ord[i] = i;
}
sort(Ord + 1, Ord + 1 + N, Cmp);
int Ok = 0, Lst = 0;
while (Ok < N) {
if (l == r) {
for (int i = Lst + 1; i <= N; i ++) {
int Now = Ord[i];
if (!Flag[Now]) {
Flag[Now] = 1;
F[Now] = K[Now];
D[++ r] = Now;
Lst = i;
break;
}
}
}
while (l < r) {
Ok ++;
int Now = D[++ l];
F[Now] = min(F[Now], K[Now]);
for (int p = Last[Now]; p; p = Next[p]) {
int v = Go[p];
if (Flag[v]) continue;
int Cnt = Map[v][Now];
if (Cnt) {
F[v] += F[Now] * Cnt;
Map[v][Now] = 0;
Num[v] -= Cnt;
if (Num[v] == 0) D[++ r] = v, Flag[v] = 1;
}
}
}
}
printf("%lld\n", F[1]);
}