BZOJ-1179: [Apio2009]Atm

[文章目录]

Description


N, M<=500000

tarjan缩点+spfa求最长路。
发现缩点之后图变成了一个拓扑图。(并不是树!!!)然后,答案就变成了求一个合法的强连通分量使得到s路径上点权和最大。spfa求最长路

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 501000
int n,m,s,p,ans,fna;
int dfn[N],low[N],bel[N],z[N],top,tot;
bool inz[N],v[N];
int w[N];
int head[N<<1],to[N<<1],nxt[N<<1],f[N],cnt;
inline void add(int x,int y)
{
    to[++cnt]=y;
    nxt[cnt]=head[x];
    head[x]=cnt;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++tot; 
    z[++top]=x; inz[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        if(!dfn[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
        else if(inz[to[i]]) low[x]=min(low[x],dfn[to[i]]);
    }
    if(low[x]==dfn[x])
    {
        ans++;int t;
        do
        {
            t=z[top--];
            inz[t]=0;
            bel[t]=ans;
        }while(t!=x);
    }
}
int dis[N<<1];
bool vis[N<<1];
void spfa(int x)
{
    queue<int>q;
    memset(dis,0xef,sizeof dis);
    dis[x]=0; q.push(x); vis[x]=1;
    while(!q.empty())
    {
        x=q.front(); q.pop(); vis[x]=0;
        for(int i=head[x];i;i=nxt[i])
            if(dis[to[i]]<dis[x]+f[to[i]-n])
            {
                dis[to[i]]=dis[x]+f[to[i]-n];
                if(!v[to[i]]) q.push(to[i]),vis[to[i]]=1;
            }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        f[bel[i]]+=x;
    }
    scanf("%d%d",&s,&p);
    for(int i=1;i<=p;i++)
    {
        scanf("%d",&x);
        v[bel[x]]=1;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=nxt[j])
            if(bel[i]!=bel[to[j]])
                add(bel[i]+n,bel[to[j]]+n);
    }
    spfa(bel[s]+n);
    for(int i=1;i<=ans;i++)
        if(v[i]) fna=max(fna,dis[i+n]);
    printf("%d",fna+f[bel[s]]);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注