题目大意:给出一张有向图,每一个节点有一个权值,经过一次之后会取走节点上的权值。有一个原点,多个汇点,问最多能收获多少权值。
思路:做一次Tarjan将图变成拓扑图,然后直接跑SPFA+Heap,比较慢,但是用了高大上的namespace,很开心。
CODE:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 500000
using namespace std;
struct Complex{
int pos,len;
Complex(int _,int __):pos(_),len(__) {}
bool operator <(const Complex &a)const {
return len < a.len;
}
};
int points,edges,cnt;
int head[MAX],total;
int next[MAX],aim[MAX];
int src[MAX];
int S,T;
int deep[MAX],low[MAX],_total;
bool v[MAX];
int changed[MAX],sum[MAX],scc;
int stack[MAX],top;
bool in_stack[MAX];
namespace SPA{
int head[MAX],total;
int next[MAX],aim[MAX];
int f[MAX];
inline void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
int SPFA(int st,int ed)
{
static priority_queue<Complex> q;
q.push(Complex(st,sum[st]));
f[st] = sum[st];
while(!q.empty()) {
Complex temp = q.top(); q.pop();
int x = temp.pos;
if(f[x] > temp.len) continue;
for(int i = head[x]; i; i = next[i])
if(f[aim[i]] < f[x] + sum[aim[i]]) {
f[aim[i]] = f[x] + sum[aim[i]];
q.push(Complex(aim[i],f[aim[i]]));
}
}
return f[ed];
}
}
inline void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
void Tarjan(int x)
{
deep[x] = low[x] = ++_total;
v[x] = true;
stack[++top] = x;
in_stack[x] = true;
for(int i = head[x]; i; i = next[i]) {
if(!v[aim[i]])
Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]);
else if(in_stack[aim[i]])
low[x] = min(low[x],deep[aim[i]]);
}
if(low[x] == deep[x]) {
++scc;
int temp;
do {
temp = stack[top--];
in_stack[temp] = false;
sum[scc] += src[temp];
changed[temp] = scc;
}while(temp != x);
}
}
int main()
{
cin >> points >> edges;
for(int x,y,i = 1; i <= edges; ++i) {
scanf("%d%d",&x,&y);
Add(x,y);
}
for(int i = 1; i <= points; ++i)
scanf("%d",&src[i]);
for(int i = 1; i <= points; ++i)
if(!v[i])
Tarjan(i);
for(int x = 1; x <= points; ++x)
for(int i = head[x]; i; i = next[i])
if(changed[x] != changed[aim[i]])
SPA::Add(changed[x],changed[aim[i]]);
cin >> S >> cnt;
for(int x,i = 1; i <= cnt; ++i) {
scanf("%d",&x);
SPA::Add(changed[x],scc + 1);
}
cout << SPA::SPFA(changed[S],scc + 1) << endl;
return 0;
}