锰锌球煮,wa了#3
查看原帖
锰锌球煮,wa了#3
577999
Happy_GG楼主2022/8/18 17:08

wa了#3 94pots 求各位大佬帮我康康Orz

思路就是tarjan + 拓扑

缩点后新建从酒馆指向市中心的图

然后就是从酒馆开始拓扑

大概就是酱紫

/*
        No    ACCEPT
        No    ACCEPT         
        No    ACCEPT
*/
#include<bits/stdc++.h>
#define long long int
using namespace std;
const int N=5e5+10;
int head[N],to[N],nxt[N],e[N],tot;
int head2[N],to2[N],nxt2[N],tot2;
int n,m,S,P;
int dp[N],anss;//到达dp[i]这个点所能抢劫的最多money
bool bar[N],vis[N],v[N];
int dfn[N],times,low[N],id[N],scc_cnt,scc_size[N];
stack <int> q;
inline int read(){
    char ch=getchar();
    int ans=0,t=1;
    while(ch<'0'||ch>'9'){
        if(ch=='-') t=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        ans=ans*10+(ch-'0');
        ch=getchar();
    }
    return ans*t;
}
void add(int x,int y){
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void add2(int x,int y){
    to2[++tot2]=y;
    nxt2[tot2]=head2[x];
    head2[x]=tot2;
}
void tj(int x){
    v[x]=true;
    dfn[x]=low[x]=++times;
    q.push(x);
    vis[x]=true;
    for(int i=head[x];i;i=nxt[i]){
        int y=to[i];
        if(!dfn[y]){
            tj(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y]) low[x]=min(low[x],dfn[y]);
    }
    if(dfn[x]==low[x]){
        scc_cnt++;
        int tp=0;
        do{
            tp=q.top();
            q.pop();
            vis[tp]=false;
            id[tp]=scc_cnt;
            scc_size[scc_cnt]+=e[tp]; //该缩点中所有ATM的钱
        }while(tp!=x);
    }
}
void dfs(int x){
    dp[x]+=scc_size[x];
    int cntt=0;//抢劫的小钱钱
    for(int i=head2[x];i;i=nxt2[i]){
        int y=to2[i];
        if(y==id[S]){
            dp[x]+=scc_size[id[S]];//到达市中心
            return;
        }
        if(!dp[y]) dfs(y); //如果算过一个点的就不再计算,直接利用
        cntt=max(cntt,dp[y]);
    }
    dp[x]+=cntt;
}
signed main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
    }
    for(int i=1;i<=n;i++) e[i]=read();

    cin>>S>>P;
    tj(S);

    for(int i=1;i<=P;i++){
        int x;
        cin>>x;
        bar[id[x]]=true;
    }//酒馆

    for(int i=1;i<=n;i++){
        if(!id[i]) continue;
        for(int j=head[i];j;j=nxt[j]){
            int y=to[j];
            if(id[y]==id[i]) continue;
            add2(id[y],id[i]);
        }
    }//倒着建图 从酒馆指向终点

    for(int i=1;i<=scc_cnt;i++){
        if(bar[i]&&!dp[i]) dfs(i);
        if(bar[i]) anss=max(anss,dp[i]);
    }
    cout<<anss;
    return 0;
}
2022/8/18 17:08
加载中...