思路:用tarjan进行缩点处理,在缩点后的图上依次跑SPFA求最短路径
//2023/7/4
//别着急,先通读一遍题目
//别忘了开long long
//写完先看一遍怎么降复杂度
//要么开全局变量要么给定初值
//想想看,有什么情况需要特判
//看看数组开的够不够大
//std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int INF=0x3f3f3f3f;
int num,ans;
struct link{
int from,to,w,next;
}edge[2*MAXN];
struct star{
int from,to,w,next;
}bian[2*MAXN];
int head[MAXN],dfn[MAXN],low[MAXN],id[MAXN],tot[MAXN],staing[MAXN],du[MAXN];
int point[MAXN],dis[MAXN],vis[MAXN],tou[MAXN];
int escnt,tim,root,ancnt;
stack<int> stk;
void add_1(int u,int v)
{
edge[++escnt].from=u;
edge[escnt].to=v;
edge[escnt].next=head[u];
head[u]=escnt;
}
void add_2(int u,int v)
{
bian[++ancnt].from=u;
bian[ancnt].to=v;
bian[ancnt].next=tou[u];
tou[u]=ancnt;
}
void tarjan(int u)
{
dfn[u]=low[u]=++tim;
stk.push(u);
staing[u]=1;
for (int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(dfn[v]==0){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(staing[u]){
low[u]=min(low[u],dfn[v]);
}
}
int k;
if(low[u]==dfn[u]){
++num;
do{
k=stk.top();
stk.pop();
staing[k]=0;
id[k]=num;
tot[num]+=point[k];
}while(u!=k);
}
}
int n,m,x,y;
int SPFA(int sid)
{
int sum=0;
for (int i=1;i<=n;i++)
{
dis[i]=-INF;
}
queue<int> que;
memset(vis,false,sizeof(vis));
dis[sid]=0;
vis[sid]=1;
que.push(sid);
while(!que.empty())
{
int cp=que.front();
que.pop();
vis[cp]=false;
sum=max(sum,dis[cp]+tot[cp]);
for (int i=tou[cp];i!=-1;i=bian[i].next)
{
int eto=bian[i].to;
int ew=bian[i].w;
if(dis[eto]<dis[cp]+ew)
{
dis[eto]=dis[cp]+ew;
if(!vis[eto])
{
que.push(eto);
vis[eto]=true;
}
}
}
}
return sum;
}
int main()
{
memset(head,-1,sizeof(head));
memset(tou,-1,sizeof(tou));
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>point[i];
for (int i=1;i<=m;i++){
cin>>x>>y;
add_1(x,y);
}
for (int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i);
}
for (int i=1;i<=n;i++){
for (int j=head[i];j!=-1;j=edge[j].next){
int v=edge[j].to;
if(id[j]==id[v]) continue;
add_2(id[j],id[v]);
}
}
for (int i=1;i<=num;i++){
ans=max(SPFA(i),ans);
}
cout<<ans<<endl;
return 0;
}