码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1179

时间:2015-07-28 00:45:58      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:

题解再次来自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 }
View Code

1179: [Apio2009]Atm

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 1921  Solved: 763
[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的单向的道路到达其中的至少一个酒吧。

 

Source

 
[Submit][Status][Discuss]

bzoj1179

标签:

原文地址:http://www.cnblogs.com/chensiang/p/4681610.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!