[BZOJ 1179][Apio2009]Atm:Tarjan+SPFA

来源:互联网 发布:天一混元青岛店淘宝 编辑:程序博客网 时间:2024/05/21 19:22

点击这里查看原题

先缩点,然后把负的点权当做边权,用SPFA求最短路(取反即为最长路),在所有有酒吧的点中取dis最大的点即为答案

/*User:SmallLanguage:C++Problem No.:1179*/#include<bits/stdc++.h>#define ll long long#define inf 999999999using namespace std;const int M=5e5+5;int n,m,c[M],s,p,dis[M],f[M],C[M],fir[M],FIR[M],tot,dfn[M],low[M],cnt,ans;bool vis[M],is_end[M];stack<int> ss;struct edge{    int v,nex;}e[M],E[M];void add(int u,int v,int i){    e[i]=(edge){v,fir[u]};    fir[u]=i;}void Add(int u,int v){    E[++tot]=(edge){v,FIR[u]};    FIR[u]=tot;}void dfs(int u){    dfn[u]=low[u]=++tot;    ss.push(u);    vis[u]=1;    for(int i=fir[u];i;i=e[i].nex){        int v=e[i].v;        if(!dfn[v]){            dfs(v);            low[u]=min(low[u],low[v]);        }        else if(vis[v]) low[u]=min(low[u],dfn[v]);    }    if(low[u]==dfn[u]){        cnt++;        while(1){            int q=ss.top();            ss.pop();            vis[q]=0;            f[q]=cnt;            C[cnt]+=c[q];            if(q==u) break;        }    }}int main(){    freopen("data.in","r",stdin);//    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        int u,v;        scanf("%d%d",&u,&v);        add(u,v,i);    }    for(int i=1;i<=n;i++)        scanf("%d",&c[i]);    scanf("%d%d",&s,&p);    for(int i=1;i<=p;i++){        int x;        scanf("%d",&x);        is_end[x]=1;    }    for(int i=1;i<=n;i++)        if(!dfn[i]) dfs(i);    tot=0;    for(int i=1;i<=n;i++){        for(int j=fir[i];j;j=e[j].nex){            int v=e[j].v;            if(f[i]!=f[v]) Add(f[i],f[v]);        }    }    memset(dis,63,sizeof(dis));    queue<int> q;    q.push(f[s]);    vis[f[s]]=1;    dis[f[s]]=-C[f[s]];    while(!q.empty()){        int u=q.front();        q.pop();        vis[u]=0;        for(int i=FIR[u];i;i=E[i].nex){            int v=E[i].v;            if(dis[v]>dis[u]-C[v]){                dis[v]=dis[u]-C[v];                if(!vis[v]){                    vis[v]=1;                    q.push(v);                }            }        }    }    for(int i=1;i<=n;i++) if(is_end[i]) ans=max(ans,-dis[f[i]]);    printf("%d\n",ans);    return 0;}
0 0
原创粉丝点击