1179: [Apio2009]Atm

76 篇文章 0 订阅
50 篇文章 0 订阅

Time Limit: 15 Sec   Memory Limit: 162 MB
Submit: 2220   Solved: 898
[ Submit][ Status][ Discuss]

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的单向的道路到达其中的至少一个酒吧。


题解:

tarjan缩点之后spfa解之。

//自己的代码有点丑,看了不好(私藏了),代之黄学长的(一直mod的神犇)

code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,S,p,tim,scc,top,cnt,ans;
int head[500005],h[500005],f[500005];
int belong[500005],v[500005];
int c[500005],dfn[500005],low[500005],q[500005];
bool inq[500005];
struct data{int to,next;}e[500005];
struct edge{int to,next;}ed[500005];
void insert(int u,int v){
	e[++cnt].to=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void ins(int u,int v){
	ed[++cnt].to=v;
	ed[cnt].next=h[u];
	h[u]=cnt;
}
void tarjan(int x){
    int now=0;
    dfn[x]=low[x]=++tim;
    q[++top]=x;inq[x]=1;
    for(int i=head[x];i;i=e[i].next)
        if(!dfn[e[i].to]){
			tarjan(e[i].to);
			low[x]=min(low[x],low[e[i].to]);
		}else if(inq[e[i].to])low[x]=min(low[x],dfn[e[i].to]);
	if(low[x]==dfn[x]){
		scc++;
        while(now!=x){
            now=q[top];
			top--;
            belong[now]=scc;
            v[scc]+=c[now];
            inq[now]=0;
        }
    }
}
void rebuild(){
	cnt=0;
	for(int i=1;i<=n;i++)
		for(int j=head[i];j;j=e[j].next)
			if(belong[i]!=belong[e[j].to])
				ins(belong[i],belong[e[j].to]);
}
void spfa(){
    int t=0,w=1;
    q[t]=belong[S];inq[belong[S]]=1;
    f[belong[S]]=v[belong[S]];
    while(t!=w){
		int now=q[t];t++;if(t==500000)t=0;
        for(int i=h[now];i;i=ed[i].next){
    	    if(f[now]+v[ed[i].to]>f[ed[i].to]){
    	        f[ed[i].to]=f[now]+v[ed[i].to];
    	    	if(!inq[ed[i].to]){
					inq[ed[i].to]=1;q[w++]=ed[i].to;
					if(w==500000)w=0;
				}
    	    }
    	}
    	inq[now]=0;
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
		cin>>u>>v;
        insert(u,v);
    }
    for(int i=1;i<=n;i++)scanf("%d",c+i);
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    cin>>S>>p;
    rebuild();
    spfa();
    for(int i=1;i<=p;i++){
        int x;
		cin>>x;
        if(f[belong[x]]>ans)ans=f[belong[x]];
    }
    printf("%d",ans);
return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值