[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.