传送门
把强连通分量缩成一个点,然后对DAG跑拓扑排序,处理出最大值。
其实是【模板】缩点+【模板】拓扑排序

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define up(a,b,c) for (int a(b),end##a(c);a<=end##a;++a)
#define down(a,c,b) for (int a(b),end##a(c);a>=end##a;--a)
#define uup(a,c,b) for (int a(b),end##a(c);a<=end##a;++a)
#define udown(a,b,c) for (int a(b),end##a(c);a>=end##a;--a)
using namespace std;
int read(){
    char s;
    int k=0,base=1;
    while((s=getchar())!='-'&&s!=EOF&&!(s>='0'&&s<='9'));
    if(s==EOF)exit(0);
    if(s=='-')base=-1,s=getchar();
    while(s>='0'&&s<='9'){
        k=k*10+(s-'0');
        s=getchar();
    }
    return k*base;
}
void write(int x){
    if(x<0){
        putchar('-');
        write(-x);
    }
    else{
        if(x/10)write(x/10);
        putchar(x%10+'0');
    }
}
int dfn[10242],low[10242],col[10242],stk[10242],instk[10242],top,s,c,vis[10242],rd[10242],cd[10242];
int a[10242],w[10242];
int beg[10242],lst[102424],to[102424],e,beg1[10242],lst1[102424],to1[102424],e1;
int n,m;
void Tarjan(int x){//找出强连通分量,并且给每个强连通分量标号
    dfn[x]=low[x]=++s;
    stk[++top]=x;
    instk[x]=1;
    int t;
    for(int i=beg[x];i;i=lst[i]){
        t=to[i];
        if(!dfn[t]){
            Tarjan(t);
            low[x]=low[x]<low[t]?low[x]:low[t];
        }
        else if(instk[t])low[x]=min(low[x],dfn[t]);
    }
    if(dfn[x]==low[x]){
        ++c;
        do{
            t=stk[top];
            instk[t]=0;
            col[t]=c;//col[t]表示t属于第col[t]个强连通分量
            w[c]+=a[t];
            --top;
        }while(t!=x);
    }
}
void SD(){//重新加边,缩点结束
    up(i,1,n){
        for(int j=beg[i];j;j=lst[j]){
            if(col[i]!=col[to[j]]){
                to1[++e1]=col[to[j]];
                lst1[e1]=beg1[col[i]];
                beg1[col[i]]=e1;
                ++cd[col[i]];
                ++rd[col[to[j]]];
            }
        }
    }
}
int f[10242];//f[x]表示以第i个强连通分量结尾的路径权值的最大值。
int chkmax(int &a,int b){
    a=a>b?a:b;
}
void Top(int x){//DFS版拓扑排序
    vis[x]=1;
    f[x]+=w[x];
    for(int i=beg1[x];i;i=lst1[i]){
        chkmax(f[to1[i]],f[x]);
        if(!(--rd[to1[i]]))Top(to1[i]);
    }
}
int main(){
    n=read();m=read();
    up(i,1,n)a[i]=read();
    int u,v;
    while(m){
        --m;
        u=read();v=read();
        to[++e]=v;
        lst[e]=beg[u];
        beg[u]=e;
    }
    up(i,1,n)if(!dfn[i])Tarjan(i);
    SD();
    up(i,1,c)if(!vis[i]&&!rd[i])Top(i);
    int ans=0;
    up(i,1,c)chkmax(ans,f[i]);
    printf("%d\n",ans);
    return 0;
}

标签: 模板, 强连通分量,缩点

添加新评论