UOJ Logo zgjkt的博客

博客

【bzoj1179】Atm

2015-09-09 13:43:43 By zgjkt

题目大意

数据范围

$0\leqslant n,m\leqslant 500000$,每个ATM机中可取的钱数为一个非负整数且$\leqslant$4000


题解

题目描述已经很明确的说明了每条道路可以经过多次,因此先tarjan缩点把图重建成DAG图

然后再用SPFA跑一边最长路,然后统计每个酒吧为终点的最长路的最大值就行了


程序

#include<cstdio>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define maxn 505000
using namespace std;

struct edge{int to,next;}e[maxn],e2[maxn];
int last[maxn],last2[maxn],c[maxn],c2[maxn];
int dfn[maxn],low[maxn],q[maxn],flag[maxn];
int belong[maxn],d[maxn];
int n,m,s,p,dt,et,et2,top,scc;
inline void addedge(int u,int v){e[++et].to=v;e[et].next=last[u];last[u]=et;}
inline void addedge2(int u,int v){e2[++et2].to=v;e2[et2].next=last2[u];last2[u]=et2;}
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void tarjan(int x){
    dfn[x]=low[x]=++dt;
    q[++top]=x;flag[x]=1;
    for(int i=last[x];i;i=e[i].next)
        if (!dfn[e[i].to]) {tarjan(e[i].to);low[x]=min(low[x],low[e[i].to]);}
        else if (flag[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
    if (low[x]==dfn[x]){
        ++scc;int now=0;
        while (now!=x){
            now=q[top--];
            belong[now]=scc;
            c2[scc]+=c[now];
            flag[now]=0;
        }
    }
}
inline void rebuild(){
    For(u,1,n)
        for(int i=last[u];i;i=e[i].next)
            if (belong[u]!=belong[e[i].to]) addedge2(belong[u],belong[e[i].to]);
}
inline void spfa(){
    queue <int> q2;memset(flag,0,sizeof(flag));
    d[belong[s]]=c2[belong[s]];q2.push(belong[s]);flag[belong[s]]=1;
    int z=0;
    while (!q2.empty()){
        z++;
        int h=q2.front();q2.pop();flag[h]=0;
        for(int i=last2[h];i;i=e2[i].next)
            if (d[h]+c2[e2[i].to]>d[e2[i].to]){
                d[e2[i].to]=d[h]+c2[e2[i].to];
                if (!flag[e2[i].to]) {q2.push(e2[i].to);flag[e2[i].to]=1;}
            }
    }
}
int main(){
    n=read();m=read();
    For(i,1,m){
        int x=read(),y=read();
        addedge(x,y);
    }
    For(i,1,n) c[i]=read();
    For(i,1,n) if (!dfn[i]) tarjan(i);
    s=read();p=read();int ans=0;
    rebuild();
    spfa();
    For(i,1,p){
        int x=read();
        if (d[belong[x]]>ans) ans=d[belong[x]];
    }
    printf("%d\n",ans);
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。