bzoj 1179(强连通+spfa)

8 篇文章 0 订阅
2 篇文章 0 订阅

1179: [Apio2009]Atm

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


解题思路:先强连通,再用spfa(可把边权改为负数再求最短路)


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn=500001;
int len,len1,S,tcc,head,size,n,m,tail;
int to[500001],to1[500001],next[500001],next1[500001];
int h[500001],h1[500001],dfn[500001],twf[500001],dui[500001],zhi[500001];
int q[500001],pan[500001],v[500001],dis[500001];
bool b[500001];


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


void insert(int x,int y) 
 {  
   ++len; to[len]=y; next[len]=h[x]; h[x]=len;
 }


void insert1(int x,int y)
 {
  ++len1; to1[len1]=y; next1[len1]=h1[x]; h1[x]=len1;
 }


void dfs(int now)
 {
  ++tcc; ++head; q[head]=now; dfn[now]=twf[now]=tcc; pan[now]=1;
  int u=h[now];
  while (u!=0)
  {
  if (pan[to[u]]==0)
  {
   dfs(to[u]);
}
if (pan[to[u]]==1)
    {
    twf[now]=min(twf[now],twf[to[u]]);
  }
u=next[u];
 }
if (dfn[now]==twf[now])
{
++size; 
while (q[head]!=now)
{
--head;
dui[q[head+1]]=size; zhi[size]+=v[q[head+1]];
pan[q[head+1]]=2;
 }
--head; dui[now]=size; zhi[size]+=v[now]; pan[now]=2;
}
 }


int main()
{
freopen("large-tree-0.in","r",stdin);
freopen("main.out","w",stdout);
n=read(); m=read();
for (int i=1;i<=m;++i)
     {
      int x=read(); int y=read();
      insert(x,y);
}
for (int i=1;i<=n;++i)
{
v[i]=read();
}
S=read();
size=0; head=0; tcc=0;
memset(dfn,0,sizeof(dfn));
memset(twf,0,sizeof(twf));
memset(pan,0,sizeof(pan));
for (int i=1;i<=n;++i)
if (pan[i]==0)
 {
  dfs(i);
 }
for (int i=1;i<=n;++i)
{
int u=h[i];
while (u!=0)
{
int u1=dui[i]; int u2=dui[to[u]];
if (u1!=u2)
{
insert1(u1,u2);
}
u=next[u];
 }
}
memset(dis,0x7f,sizeof(dis));
memset(b,true,sizeof(b));
   tail=0; head=0; ++tail; q[tail]=dui[S]; dis[dui[S]]=-zhi[dui[S]]; b[dui[S]]=false;
while(head<tail)
{
   head=(head+1)%maxn;
int u=h1[q[head]];
while (u!=0)
{
   if (dis[q[head]]-zhi[to1[u]]<dis[to1[u]])
 {
   dis[to1[u]]=dis[q[head]]-zhi[to1[u]];
   if (b[to1[u]])
    {
    b[to1[u]]=false;
    tail=(tail+1)%maxn; q[tail]=to1[u];
}
 }
u=next1[u];
 }
b[q[head]]=true;
}
int q=read();
int ans=-1;
for (int i=1;i<=q;++i)
 {
  int x=read();
  if (dui[x]==dui[S]) ans=max(ans,zhi[S]);else
  ans=max(ans,-dis[dui[x]]);
 }
printf("%d",ans);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值