[Apio2009]Atm
Time Limit:15000MS Memory Limit:165536K
Total Submit:4 Accepted:4
Case Time Limit:1500MS
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求最长路搞定。
Q:SPFA不会出环挂掉么?
A:都Tarjan了,哪里还有环……直接变成一棵树了……
Q:为什么我在OJ上交会WA或者TLE……
A:当时比赛貌似开8M系统栈,OJ无法给开这么大的……本机测试(fpc 2.4.2)每组数据都可以在0.4s内出解。
附:APIO数据下载 http://www.apio.olympiad.org/2009/
Program Apio_2009_ATM;
type rec=record
endv,next:longint;
end;
var edge,map:Array[1..500000]of rec;
father2,dist,order,atm,money,v,dfn,low,stack,father:Array[1..500000]of longint;
Instack,vis:array[1..500000]of boolean;
q:Array[0..10000000]of longint;
n,m,s,p,total,tot,index,module,ans:longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a);
exit(b);
end;
procedure addedge(s,t:longint);
begin
inc(total);
edge[total].endv:=t;
edge[total].next:=father[s];
father[s]:=total;
end;
procedure addedge2(s,t:longint);
begin
inc(total);
map[total].endv:=t;
map[total].next:=father2[s];
father2[s]:=total;
end;
procedure init;
var i,a,b:longint;
begin
fillchar(father,sizeof(father),$ff);
readln(n,m);
for i:=1 to m do
begin
readln(a,b);
addedge(a,b);
end;
for i:=1 to n do readln(money[i]);
readln(s,p);
for i:=1 to p do read(atm[i]);
end;
procedure tarjan(x:longint);
var p:longint;
begin
inc(index);
dfn[x]:=index;
low[x]:=index;
Instack[x]:=true;
inc(tot);
stack[tot]:=x;
p:=father[x];
while p>0 do
begin
if dfn[edge[p].endv]=0 then
begin
tarjan(edge[p].endv);
low[x]:=min(low[x],low[edge[p].endv]);
end
else if instack[edge[p].endv] then
low[x]:=min(low[x],dfn[edge[p].endv]);
p:=edge[p].next;
end;
if dfn[x]=low[x] then
begin
inc(module);
repeat
order[stack[tot]]:=module;
Instack[stack[tot]]:=false;
dec(tot);
until stack[tot+1]=x;
end;
end;
procedure BuildNewGraph;
var i,p:longint;
begin
fillchar(father2,sizeof(father2),$ff);
for i:=1 to n do inc(v[order[i]],money[i]);
total:=0;
for i:=1 to n do
begin
p:=father[i];
while p>0 do
begin
if order[i]<>order[edge[p].endv] then addedge2(order[i],order[edge[p].endv]);
p:=edge[p].next;
end;
end;
end;
procedure compress;
var i:longint;
begin
fillchar(dfn,sizeof(dfn),0);
fillchar(low,sizeof(low),0);
fillchar(Instack,sizeof(Instack),false);
tot:=0;index:=0;
for i:=1 to n do
if dfn[i]=0 then Tarjan(i);
BuildNewGraph;
end;
procedure spfa(s:longint);
var head,tail,p,now:longint;
begin
fillchar(vis,sizeof(vis),false);
head:=0;tail:=0;
q[head]:=s;vis[s]:=true;
dist[s]:=v[s];
while head<=tail do
begin
now:=q[head];
p:=father2[now];
while p>0 do
begin
if dist[map[p].endv]<dist[now]+v[map[p].endv] then
begin
dist[map[p].endv]:=dist[now]+v[map[p].endv];
if not vis[map[p].endv] then
begin
vis[map[p].endv]:=true;
tail:=(tail+1)mod 10000000;
q[tail]:=map[p].endv;
end;
end;
p:=map[p].next;
end;
head:=(head+1)mod 10000000;
vis[now]:=false;
end;
end;
procedure Print;
var i:longint;
begin
for i:=1 to p do
if dist[order[atm[i]]]>ans then ans:=dist[order[atm[i]]];
writeln(ans);
end;
begin
init;
Compress;
spfa(order[s]);
Print;
end.