易错点:
- 最深刻的孤独,也许并不是面壁者的深思。在那只有一个结点的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;
}