bzoj 3875 骑士游戏

SPFA.

设第 $i$ 只怪物的消耗为 $f(i)$ ,则
$$
f(i)=\min\lbrace K_i,S_i+\sum_{j\in son(i)} f(j) \rbrace
$$
这个转移可能成环,存在后效性,用 SPFA 去转移,一个点更新之后,要把所有连向它的点入队更新答案.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//%std
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
inline ll read()
{
ll out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=2e5+10;
int n,in[MAXN];
ll dis[MAXN],s[MAXN];
vector<int> sons[MAXN],fa[MAXN];
queue<int> q;
void SPFA()
{
for(int i=1;i<=n;++i)
{
q.push(i);
in[i]=1;
}
while(!q.empty())
{
int u=q.front();
q.pop();
in[u]=false;
ll tmp=s[u];
for(int i=0;i<(signed)(sons[u].size());++i)
tmp+=dis[sons[u][i]];
if(tmp<dis[u])
{
dis[u]=tmp;
for(int i=0;i<(signed)(fa[u].size());++i)
{
int v=fa[u][i];
if(!in[v])
{
q.push(v);
in[v]=1;
}
}
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;++i)
{
s[i]=read();
dis[i]=read();
int m=read();
for(int k=0;k<m;++k)
{
int j=read();
sons[i].push_back(j);
fa[j].push_back(i);
}
}
SPFA();
cout<<dis[1]<<endl;
return 0;
}