题目地址


易错点:

  • 最深刻的孤独,也许并不是面壁者的深思。在那只有一个结点的scc里,不知存放着多少份无处安放的彷徨.
  • 世界上最遥远的距离不是你和我,而是你在搜索树上的那一头,我却在搜索树的这一头。那被有向图规则所束缚着的可达性,令我们天人永隔.

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring> 
using namespace std;
const int MAXN=1000010,MAXM=1000010;
int n;
struct Edge{
    int from,to,nxt;
}firstEdge[MAXM];
int firstHead[MAXN],firstCnt=0;
void addFirstEdge(int u,int v){
    firstEdge[++firstCnt].from=u;
    firstEdge[firstCnt].to=v;
    firstEdge[firstCnt].nxt=firstHead[u];
    firstHead[u]=firstCnt;
}
struct edge{
    int from,to,nxt;
}secondEdge[MAXM];
int secondHead[MAXN],secondCnt=0;
void addSecondEdge(int u,int v){
    secondEdge[++secondCnt].from=u;
    secondEdge[secondCnt].to=v;
    secondEdge[secondCnt].nxt=secondHead[u];
    secondHead[u]=secondCnt;
}
int low[MAXN],dfn[MAXN],tarjanDfnCnt=0;//dfs序号
int stck[MAXN],top=0;//栈
bool inc[MAXN]; 
int c[MAXN],sccCnt=0;//属于的scc 
int sum[MAXN],pointValue[MAXN];//scc权值与点权值 
void tarjan(int x){
    low[x]=dfn[x]=++tarjanDfnCnt;
    inc[x]=1;
    stck[++top]=x;
    for(int i=firstHead[x];i;i=firstEdge[i].nxt){
        int v=firstEdge[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }else if(inc[v])low[x]=min(low[x],dfn[v]);
    }
    if(low[x]==dfn[x]){
        int y;sccCnt++;
        do{
            y=stck[top--];
            c[y]=sccCnt;
            inc[y]=0;
            sum[sccCnt]+=pointValue[y]; 
        }while(x!=y);
    }
}
void rebuild(){
    for(int x=1;x<=n;x++)
        for(int i=firstHead[x];i;i=firstEdge[i].nxt){
            int v=firstEdge[i].to;
            if(c[x]!=c[v])addSecondEdge(c[x],c[v]);
        }
}
int dp[MAXN];
void Dp(int x){
    dp[x]=sum[x];
    int maxx=0;
    for(int i=secondHead[x];i;i=secondEdge[i].nxt){
        int v=secondEdge[i].to;
        if(!dp[v])Dp(v);
        maxx=max(maxx,dp[v]);
    }
    dp[x]+=maxx;
}
int main(){
    memset(dfn,0,sizeof(dfn));
    memset(dp,0,sizeof(dp));
    int m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&pointValue[i]);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addFirstEdge(u,v);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i);
    }
    rebuild();
    int ans=-1;
    for(int i=1;i<=n;i++){
        if(!dp[i])Dp(i);
        ans=max(ans,dp[i]);
    }
    printf("%d\n",ans);
    return 0;
}