标签:
题解再次来自lsj(懒得敲):
对于一个强连通分量, 一定是整个走或者不走, 所以tarjan缩点然后跑dijkstra.
1 #include<bits/stdc++.h> 2 #define clr(a,x) memset(a,x,sizeof(a)) 3 #define rep(i,l,r) for(int i=l;i<r;i++) 4 #define Rep(i,a) rep(i,0,e[a].size()) 5 #define REP(i,a) rep(i,0,e1[a].size()) 6 typedef long long ll; 7 using namespace std; 8 int read() 9 { 10 char c=getchar(); 11 int ans=0,f=1; 12 while(!isdigit(c)){ 13 if(c==‘-‘) f=-1; 14 c=getchar(); 15 } 16 while(isdigit(c)){ 17 ans=ans*10+c-‘0‘; 18 c=getchar(); 19 } 20 return ans*f; 21 } 22 struct node{ 23 int d,num; 24 inline bool operator <(const node&A)const{ 25 return d>A.d; 26 } 27 }; 28 const int maxn=500005,inf=0x7fffffff; 29 bool b[maxn],p[maxn]; 30 int dfstime,cnt,s,k,n,m,w[maxn],low[maxn],pre[maxn],scc[maxn],d[maxn],v[maxn]; 31 stack<int>S; 32 vector<int>e[maxn]; 33 vector<int>e1[maxn]; 34 priority_queue<node>Q; 35 void dfs(int a) 36 { 37 low[a]=pre[a]=++dfstime; 38 S.push(a); 39 Rep(i,a){ 40 if(!pre[e[a][i]]){ 41 dfs(e[a][i]); 42 low[a]=min(low[a],low[e[a][i]]); 43 }else if(!scc[e[a][i]]){ 44 low[a]=min(low[a],pre[e[a][i]]); 45 } 46 } 47 if(low[a]==pre[a]){ 48 ++cnt; 49 int x=0; 50 while(x!=a){ 51 x=S.top(); 52 S.pop(); 53 scc[x]=cnt; 54 w[cnt]+=v[x]; 55 b[cnt]|=p[x]; 56 } 57 } 58 } 59 void dijkstra() 60 { 61 clr(d,0); 62 d[scc[s]]=w[scc[s]]; 63 node start; 64 start.num=scc[s],start.d=w[scc[s]]; 65 Q.push(start); 66 while(!Q.empty()){ 67 node now=Q.top(); 68 Q.pop(); 69 if(now.d==d[now.num]){ 70 REP(i,now.num){ 71 if(d[now.num]+w[e1[now.num][i]]>d[e1[now.num][i]]){ 72 d[e1[now.num][i]]=d[now.num]+w[e1[now.num][i]]; 73 node next; 74 next.d=d[e1[now.num][i]]; 75 next.num=e1[now.num][i]; 76 Q.push(next); 77 } 78 } 79 } 80 } 81 } 82 int main() 83 { 84 n=read(),m=read(),cnt=dfstime=0,clr(low,0),clr(pre,0),clr(scc,0),clr(b,0),clr(p,0); 85 rep(i,0,m){ 86 int from=read(),to=read(); 87 e[from].push_back(to); 88 } 89 rep(i,1,n+1) v[i]=read(); 90 s=read(),k=read(); 91 while(k--){ 92 int t=read(); 93 p[t]=1; 94 } 95 rep(i,1,n+1){ 96 if(!scc[i]) dfs(i); 97 } 98 rep(i,1,n+1){ 99 Rep(j,i){ 100 if(scc[i]!=scc[e[i][j]]) 101 e1[scc[i]].push_back(scc[e[i][j]]); 102 } 103 } 104 dijkstra(); 105 int ans=0; 106 rep(i,1,n+1){ 107 if(b[i]) ans=max(ans,d[i]); 108 } 109 printf("%d\n",ans); 110 return 0; 111 }
第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号
输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
标签:
原文地址:http://www.cnblogs.com/chensiang/p/4681610.html