bzoj1179 [Apio2009]Atm 强连通分量缩点+spfa

Description


Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruser
i 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。Bandit
ji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他
途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的
现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口
或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。

N, M<=500000
每个ATM机中可取的钱数为一个非负整数且不超过4000。
输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。

Solution


我也就写写水题能够1A了╮(╯▽╰)╭

缩点然后spfa就可以了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>

#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))

const int N=1000005;
const int E=1000005;

struct edge {int x,y,next;} e[E];

int dis[N],stack[N],top;
int dfn[N],low[N],bel[N];
int ls[N],n,m,edCnt;
int val[N],v[N];
int queue[N];

bool vis[N],bar[N];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
}

void dfs(int now) {
    stack[++top]=now; vis[now]=1;
    dfn[now]=low[now]=++dfn[0];
    for (int i=ls[now];i;i=e[i].next) {
        if (!dfn[e[i].y]) {
            dfs(e[i].y);
            low[now]=std:: min(low[now],low[e[i].y]);
        } else if (vis[e[i].y]) {
            low[now]=std:: min(low[now],dfn[e[i].y]);
        }
    }
    if (low[now]==dfn[now]) {
        bel[0]++;
        for (int tmp=0;tmp!=now;) {
            tmp=stack[top--];
            bel[tmp]=bel[0];
            val[bel[0]]+=v[tmp];
            vis[tmp]=0;
        }
    }
}

void tarjan(int n) {
    rep(i,1,n) if (!dfn[i]) dfs(i);
    fill(ls,0);
    drp(i,edCnt,1) {
        if (bel[e[i].x]==bel[e[i].y]) continue;
        add_edge(bel[e[i].x],bel[e[i].y]);
    }
}

int spfa(int st) {
    fill(vis,0);
    queue[1]=st; dis[st]=val[st];
    for (int head=1,tail=1;head<=tail;) {
        int now=queue[head++];
        for (int i=ls[now];i;i=e[i].next) {
            if (dis[now]+val[e[i].y]>dis[e[i].y]) {
                dis[e[i].y]=dis[now]+val[e[i].y];
                if (vis[e[i].y]) continue;
                queue[++tail]=e[i].y;
                vis[e[i].y]=1;
            }
        }
        vis[now]=0;
    }
    int ret=0;
    rep(i,1,n) if (bar[i]) ret=std:: max(ret,dis[bel[i]]);
    return ret;
}

int main(void) {
    freopen("data.in","r",stdin);
    n=read(),m=read();
    rep(i,1,m) {
        int x=read(),y=read();
        add_edge(x,y);
    }
    rep(i,1,n) v[i]=read();
    int st=read(),T=read();
    rep(i,1,T) bar[read()]=1;
    tarjan(n);
    printf("%d\n", spfa(bel[st]));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/80465572