BZOJ 1179: [Apio2009]Atm【Trajan+最短路】
1179: [Apio2009]Atm
Time Limit: 15 Sec Memory Limit: 162 MB
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(最短路)。o ( ^ v ^ ) o
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 500005
using namespace std;
int n,m,top,tim,S,P,ans,moy[MAXN],low[MAXN],dfn[MAXN],stk[MAXN],fa[MAXN];
int que[MAXN],dst[MAXN],hd,tl;
bool istk[MAXN],vis[MAXN];
struct xcw{
int tot,lnk[MAXN],nxt[MAXN],son[MAXN];
void clear(){tot=0;memset(lnk,0,sizeof(lnk));memset(nxt,0,sizeof(nxt));memset(son,0,sizeof(son));}
void add(int x,int y){son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;}
}a,b;
int read(){
int ret=0;char ch=getchar();
while(ch<'0'||'9'<ch) ch=getchar();
while('0'<=ch&&ch<='9') ret=ret*10+ch-48,ch=getchar();
return ret;
}
int tarjan(int x){
low[x]=dfn[x]=++tim;
istk[x]=1;stk[++top]=x;
for(int j=a.lnk[x];j;j=a.nxt[j])
if(dfn[a.son[j]]==0) tarjan(a.son[j]),low[x]=min(low[x],low[a.son[j]]);
else if(istk[a.son[j]]) low[x]=min(low[x],dfn[a.son[j]]);
if(dfn[x]==low[x]) do{istk[stk[top]]=0,fa[stk[top]]=x;}while(stk[top--]!=x);
}
void SPFA(int x){
hd=0,que[tl=1]=x;vis[x]=1;dst[x]=moy[fa[S]];
while(hd^tl){
x=que[(++hd)%=MAXN],vis[x]=0;
for(int j=b.lnk[x];j;j=b.nxt[j])
if(dst[b.son[j]]<dst[x]+moy[b.son[j]]){
dst[b.son[j]]=dst[x]+moy[b.son[j]];
if(!vis[b.son[j]]) vis[b.son[j]]=1,que[(++tl)%=MAXN]=b.son[j];
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){int x=read(),y=read();a.add(x,y);}
for(int i=1;i<=n;i++) moy[i]=read(),fa[i]=i;
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
b.clear();
for(int i=1;i<=n;i++){
if(fa[i]^i) moy[fa[i]]+=moy[i];
for(int j=a.lnk[i];j;j=a.nxt[j]) if(fa[a.son[j]]^fa[i]) b.add(fa[i],fa[a.son[j]]);
}
S=fa[read()],P=read();
SPFA(S);
for(int i=1;i<=P;i++) ans=max(ans,dst[fa[read()]]);
printf("%d\n",ans);
return 0;
}
SOLVE