【BZOJ1179】Atm

                                 1179: [Apio2009]Atm

                                           Time Limit: 15 Sec  Memory Limit: 162 MB
                                                    Submit: 4548  Solved: 2024

Description

Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruser

i 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。Bandit

ji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他

途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的

现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口

或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个

路口,道路的连接情况如下图所示:

市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了

路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。

Input

第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。

接下来M行,每行两个整数,这两个整数都在1到N之间,

第i+1行的两个整数表示第i条道路的起点和终点的路口编号。

接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。

接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。

接下来的一行中有P个整数,表示P个有酒吧的路口的编号

N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。

输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。

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

 

解析:

       因为每条路径可重复走多次,所以世界Tarjan缩点后跑SPFA求最长路即为答案。路径长度为终点集合的点权和。

 

代码:

#include <bits/stdc++.h>
using namespace std;

const int Max=500010;
int n,m,size,s,ans,cnt,tot,Index,q;
int first[Max],First[Max],dis[Max],num[Max],low[Max],father[Max],sum[Max],a[Max],p[Max],v[Max];
struct shu{int to,next,len;};
shu edge[Max<<1];
struct tree{int to,next;};
tree Edge[Max<<1];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') {f=-1;c=getchar();}
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline void Build(int x,int y)
{
	Edge[++size].next=first[x];
	first[x]=size;
	Edge[size].to=y;
}

inline void build(int x,int y,int z)
{
	edge[++size].next=first[x];
	first[x]=size;
	edge[size].to=y;
	edge[size].len=z;
}

inline void tarjan(int point)
{
   low[point] = num[point] = ++Index;
   p[++tot]=point;
   v[point]=1;
   for(int u=first[point];u;u=Edge[u].next)
   {
   	 if(!num[Edge[u].to]) {tarjan(Edge[u].to);low[point]=min(low[Edge[u].to],low[point]);}
   	 if(v[Edge[u].to]) low[point]=min(num[Edge[u].to],low[point]);
   }

   if(low[point]==num[point])
   {
   	 cnt++;
   	 while(1)
   	 {
   	   int x=p[tot--];
   	   v[x]=0;
   	   father[x]=cnt;
   	   sum[cnt] += a[x];
   	   if(x==point) break;
   	 }
   }
}


inline void SPFA()
{
	memset(p,0,sizeof(p));
	memset(dis,0,sizeof(dis));
    int head=0,tail=1;
    p[1]=father[s];
    dis[father[s]]=sum[father[s]];
    while(head < tail)
    {
      int point=p[++head];
      v[p[head]]=0;
      for(int u=first[point];u;u=edge[u].next)
      {
      	int to=edge[u].to;
        if(dis[to] < dis[point]+edge[u].len)
        {
          dis[edge[u].to]=dis[point]+edge[u].len;
    	  if(!v[to])
    	  {
    	    v[to]=1;
    	    p[++tail]=to;
    	  }
    	}
   	   }
    }
}

inline int mx(int x,int y){return x > y ? x : y;}

int main()
{
	n=get_int(),m=get_int();
	for(int i=1;i<=m;i++)
	{
	  int x=get_int(),y=get_int();
	  Build(x,y);
	}
	for(int i=1;i<=n;i++) a[i] = get_int();
	for(int i=1;i<=n;i++) if(!num[i]) tarjan(i);

	s=get_int(),q=get_int(),size=0;
	memcpy(First,first,sizeof(first));
	memset(first,0,sizeof(first));
	for(int i=1;i<=n;i++)
	  for(int u=First[i];u;u=Edge[u].next)
	    if(father[i] != father[Edge[u].to])
		{
		  int to=Edge[u].to;
		  build(father[i] , father[to] , sum[father[to]]);
	    }

	SPFA();

	for(int i=1;i<=q;i++) {int x=get_int();ans = mx(ans ,dis[father[x]]);}
	cout<<ans<<"\n";

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值