题目大意:给出一张有向图,每一个节点有一个权值,经过一次之后会取走节点上的权值。有一个原点,多个汇点,问最多能收获多少权值。
思路:做一次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; }
BZOJ 1179 APIO 2009 Atm Tarjan+SPFA
原文地址:http://blog.csdn.net/jiangyuze831/article/details/41545341