![[BZOJ1179] [Apio2009]Atm(tarjan缩点 + spfa) [BZOJ1179] [Apio2009]Atm(tarjan缩点 + spfa)](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700)
题意
N个点M条边的有向图
每个点有点权
从某一个结点出发
问能获得的最大点权和
一个点的点权最多被计算一次
N<=500000 M<=500000
思路
先tarjan缩点,然后就形成一个dag,无环,所以直接spfa求最长路就行。
也可以先缩点,然后拓扑排序 + dp 搞。
代码
#include <map>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream> const int MAXN = ;
int n, m, s, p, cnt, cnt1, tim, sz, ans;
int head[MAXN], to[MAXN], next[MAXN], head1[MAXN], to1[MAXN], next1[MAXN];
int a[MAXN], dfn[MAXN], low[MAXN], belong[MAXN], val[MAXN], dis[MAXN];
bool ins[MAXN], vis[MAXN];
std::map <int, int> map1[MAXN];
std::stack <int> S;
std::queue <int> q; inline int max(int x, int y)
{
return x > y ? x : y;
} inline int min(int x, int y)
{
return x < y ? x : y;
} inline int read()
{
int f = , x = ;
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -;
for(; isdigit(ch); ch = getchar()) x = (x << ) + (x << ) + ch - '';
return f * x;
} inline void add(int x, int y)
{
to[cnt] = y;
next[cnt] = head[x];
head[x] = cnt++;
} inline void add1(int x, int y)
{
to1[cnt1] = y;
next1[cnt1] = head1[x];
head1[x] = cnt1++;
} inline void dfs(int u)
{
int i, v;
S.push(u);
ins[u] = ;
dfn[u] = low[u] = ++tim;
for(i = head[u]; i ^ -; i = next[i])
{
v = to[i];
if(!dfn[v])
{
dfs(v);
low[u] = min(low[u], low[v]);
}
else if(ins[v]) low[u] = min(low[u], dfn[v]);
}
if(!(low[u] ^ dfn[u]))
{
sz++;
do
{
v = S.top();
S.pop();
belong[v] = sz;
ins[v] = ;
}
while(u ^ v);
}
} inline void spfa()
{
int i, u, v;
dis[belong[s]] = val[belong[s]];
q.push(belong[s]);
vis[belong[s]] = ;
while(!q.empty())
{
u = q.front();
q.pop();
vis[u] = ;
for(i = head1[u]; i ^ -; i = next1[i])
{
v = to1[i];
if(dis[v] < dis[u] + val[v])
{
dis[v] = dis[u] + val[v];
if(!vis[v])
{
vis[v] = ;
q.push(v);
}
}
}
}
} int main()
{
int i, x, y, u, v;
n = read();
m = read();
memset(head, -, sizeof(head));
memset(head1, -, sizeof(head1));
for(i = ; i <= m; i++)
{
x = read();
y = read();
add(x, y);
}
for(i = ; i <= n; i++) a[i] = read();
s = read();
p = read();
dfs(s);
for(i = ; i <= n; i++) val[belong[i]] += a[i];
for(u = ; u <= n; u++)
for(i = head[u]; i ^ -; i = next[i])
{
v = to[i];
if(belong[u] ^ belong[v] && !map1[belong[u]][belong[v]])
map1[belong[u]][belong[v]] = , add1(belong[u], belong[v]);
}
spfa();
for(i = ; i <= p; i++)
{
x = read();
ans = max(ans, dis[belong[x]]);
}
printf("%d\n", ans);
return ;
}