[BZOJ] 1179: [Apio2009]Atm

https://www.lydsy.com/JudgeOnline/problem.php?id=1179

 

给定一个有向图,每个点有点权,相同的点多次经过算一次,给出起点和多个终点,问取得的最大收益。

 

第一反应缩点建新图,然后就变成一个DAG了,之后就是一个最长路咯。

 

#include<iostream>
#include<cstdio>
#include<queue>

using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=500005;
const int INF=1<<30;

struct Edge{
    int from,next,to,w;
}e[MAXN],e2[MAXN];
int ecnt,head[MAXN];
inline void add(int x,int y){
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    e[ecnt].from = x;
    head[x] = ecnt;
}
int ecnt2,head2[MAXN];
inline void add2(int x,int y,int w){
    e2[++ecnt2].to = y;
    e2[ecnt2].next = head2[x];
    e2[ecnt2].w = w;
    head2[x] = ecnt2;
}
int n,m,S,num;

int savx[MAXN],savy[MAXN];
int cost[MAXN],aims[MAXN];
int bl[MAXN],dcc,val[MAXN];

int dfn[MAXN],low[MAXN],tim;
int ins[MAXN],sta[MAXN],top;
void tarjan(int x){
    dfn[x]=low[x]=++tim;
    ins[sta[++top]=x]=1;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }else if(ins[v]){
            low[x]=min(low[x],dfn[v]);
        }
    }
    if(dfn[x]!=low[x]) return;
    int elm;dcc++;
    do{
        elm=sta[top--];
        bl[elm]=dcc;
        ins[elm]=0;
        val[dcc]+=cost[elm];
    }while(elm!=x);
}

queue<int> Q;
int inq[MAXN],dis[MAXN];
void spfa(int st){
    Q.push(st);inq[st]=1;
    while(!Q.empty()){
        int top=Q.front();Q.pop();
        inq[top]=0;
        for(int i=head2[top];i;i=e2[i].next){
            int v=e2[i].to;
            if(dis[v]<dis[top]+e2[i].w){
                dis[v]=dis[top]+e2[i].w;
                if(!inq[v]) Q.push(v),inq[v]=1;
            }
        }
    }
}


int main(){
    n=rd();m=rd();
    int x,y,w;
    for(int i=1;i<=m;i++){
        x=rd();y=rd();
        add(x,y);
    }
    for(int i=1;i<=n;i++){
        cost[i]=rd();
    }
    S=rd();num=rd();
    for(int i=1;i<=num;i++){
        aims[i]=rd();
    }
    for(int i=0;i<=n;i++) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=ecnt;i++){
        int u=e[i].from,v=e[i].to;
        if(bl[u]==bl[v]) continue;
        add2(bl[u],bl[v],val[bl[v]]);
    }
    spfa(bl[S]);
    int ans=0;
    for(int i=1;i<=num;i++){
        ans=max(ans,dis[bl[aims[i]]]);
    }
    cout<<ans+val[bl[S]]<<endl;
    return 0;
}

 

posted @ 2018-07-25 09:24  GhostCai  阅读(88)  评论(0编辑  收藏  举报