[luogu3627 APIO2009] 抢掠计划 (tarjan缩点+spfa最长路)

传送门

Description

Input

第一行包含两个整数 N、M。N 表示路口的个数,M 表示道路条数。接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表示第 i 条道路的起点和终点的路口编号。接下来 N 行,每行一个整数,按顺序表示每 个路口处的 ATM 机中的钱数。接下来一行包含两个整数 S、P,S 表示市中心的 编号,也就是出发的路口。P 表示酒吧数目。接下来的一行中有 P 个整数,表示 P 个有酒吧的路口的编号。

Output

输出一个整数,表示 Banditji 从市中心开始到某个酒吧结束所能抢劫的最多 的现金总数。

Sample Input

6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1
5
1 4
4 3 5 6

Sample Output

47

HINT

50%的输入保证 N, M<=3000。所有的输入保证 N, M<=500000。每个 ATM 机中可取的钱数为一个非负整数且不超过 4000。

输入数据保证你可以从市中心 沿着 Siruseri 的单向的道路到达其中的至少一个酒吧。

Solution

很显然先缩点然后直接跑最长路就行

Code

//By Menteur_Hxy
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define M(a,b) memset(a,(b),sizeof(a))
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define E(i,u) for(register int i=head[u];i;i=nxt[i])
using namespace std;
typedef long long LL;

int read() {
    int x=0,f=1; char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
} 

const int N=500010;
bool vis[N],in[N];
int n,m,cnt,st,pl,tot,top,col;
int fr[N],nxt[N],to[N],head[N],mo[N],dfn[N],low[N],sta[N],bl[N],sum[N],pla[N];
LL ans,dis[N];
vector <int> V[N];

void tarjan(int u) { int v;
    dfn[u]=low[u]=++tot;
    sta[++top]=u;in[u]=1;
    E(i,u) if(!dfn[v=to[i]]) {
        tarjan(v);
        low[u]=min(low[u],low[v]);
    } else if(in[v]) low[u]=min(low[u],dfn[v]);
    if(dfn[u]==low[u]) {
        col++;
        while(sta[top]!=u) sum[col]+=mo[sta[top]],in[sta[top]]=0,bl[sta[top--]]=col;
        sum[col]+=mo[sta[top]],in[sta[top]]=0,bl[sta[top--]]=col;
    }
}

queue <int> Q;
void spfa(int x) {
    M(dis,0x3f);
    Q.push(x);vis[x]=1;
    dis[x]=-sum[x];
    while(!Q.empty()) {
        int u=Q.front(),v; Q.pop();
        int siz=V[u].size();
        F(i,0,siz-1) if(dis[v=V[u][i]]>dis[u]-sum[v]) {
            dis[v]=dis[u]-sum[v];
            if(!vis[v]) Q.push(v),vis[v]=1;
        }
        vis[u]=0;
    }
}

#define add(a,b) nxt[++cnt]=head[a],fr[cnt]=a,to[cnt]=b,head[a]=cnt
int main() {
    n=read(),m=read();
    F(i,1,m) {
        int a=read(),b=read();
        add(a,b);
    }
    F(i,1,n) mo[i]=read();
    st=read(),pl=read();
    F(i,1,pl) pla[i]=read();
    tarjan(st);
    F(i,1,m) { int u=fr[i],v=to[i];
        if(bl[u]==bl[v]) continue;
        V[bl[u]].push_back(bl[v]);
    }
    spfa(bl[st]);
    F(i,1,pl) if(ans<(-dis[bl[pla[i]]])) ans=(-dis[bl[pla[i]]]);
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Menteur-Hxy/p/9363426.html
今日推荐