BZOJ 1179 APIO 2009 Atm Tarjan+SPFA

题目大意:给出一张有向图,每一个节点有一个权值,经过一次之后会取走节点上的权值。有一个原点,多个汇点,问最多能收获多少权值。


思路:做一次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;
}


你可能感兴趣的:(最短路,Tarjan,bzoj,Apio2009)