啊啊啊关于这个模板我要啰嗦两句。。。。
《关于理论全懂但是不知道代码构建又看不懂别人代码这档事》
真的是辛辛苦苦花了大概2小时写的代码详细注释版
劝大家写模板时一定要注释清楚数组的含义
不然复习时真的完全看不懂。。。。。。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100010;
inline int read(){
int x=0,f=1;char ch=getchar();
if(!isdigit(ch)){if(ch==45)f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
} //快读
int n,m;//n为点的数量,m为边的数量
int val[MAXN];//强连通分量缩点后的点值
int pointadd[MAXN];
int outpoint[MAXN];//出点计数器
int degree[MAXN];//入度计数器
int dis[MAXN];//点权
int inpoint[MAXN];//入点计数器
int DFN[MAXN];//时间戳
int Low[MAXN];//u或u的子树能追溯到最早的栈中节点的序号(时间戳)
int node[MAXN];//点的集合
int Belong[MAXN];//各个顶点属于哪个强连通分量
int Stack[MAXN];//模拟栈
int inStack[MAXN];//判断点是否在栈里,0或1
int edge_cnt=0;//边的计数器
int Index=0;//序号(时间戳)(深度)
int top=0;//栈顶记录器
int Bcnt=0;//强连通分量记录器
struct Edge{
int next,to,dis;
}edge[MAXN];//边初始化
inline int add_edge(int from,int to,int dis){
edge[++edge_cnt].next=node[from];
edge[edge_cnt].to=to;
edge[edge_cnt].dis=dis;
node[from]=edge_cnt;
}//链式前向星存边
void tarjan(int u){
int i,j;
int v;
Low[u]=DFN[u]=++Index;
inStack[u]=1;
Stack[++top]=u;
for(i=node[u];i;i=edge[i].next)
{
int to=edge[i].to;
if(!DFN[to]){
tarjan(to);
Low[u]=min(Low[u],Low[to]);
}
else if(inStack[to])
Low[u]=min(Low[u],DFN[to]);
}
if(DFN[u]==Low[u]){
Bcnt++;
int j;
do{
j=Stack[top--];
inStack[j]=0;
val[Bcnt]+=pointadd[j];
Belong[j]=Bcnt;
} while(j!=u);
}
}//tarjan
inline void clear(){
memset(edge,0,sizeof(edge));
memset(node,0,sizeof(node));
edge_cnt=0;
}
inline void topsort(){
queue<int>q;//定义队列
for(int i=1;i<=Bcnt;i++)
dis[i]=0;//初始化
for(int i=1;i<=Bcnt;i++)
if(degree[i]==0) q.push(i),dis[i]=val[i];//若入度为零则出队,并且将值传递
while(q.size()!=0){//处理队列
int u=q.front();q.pop();//队首出队
for(int i=node[u];i;i=edge[i].next){//遍历出队点连接的各条边
int to=edge[i].to;
degree[to]--;//指向的点入度--
if(degree[to]==0) q.push(to);//若指向点无入度则入队
dis[to]=max(dis[to],dis[u]+edge[i].dis);//点权值和加上连接点权值比较大小考虑是否加上该点(考虑点权值为负)
}
}
int ans=0;
for(int i=1;i<=Bcnt;i++)
ans=max(ans,dis[i]);//最大值比较选取路线
printf("%d\n",ans);
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++) pointadd[i]=read();
for(int i=1;i<=m;i++){
outpoint[i]=read();
inpoint[i]=read();
add_edge(outpoint[i],inpoint[i],0);
}
for(int i=1;i<=n;i++)
if(!DFN[i]) tarjan(i);//tarjan缩点
clear();
for(int i=1;i<=m;i++){
if(Belong[outpoint[i]]==Belong[inpoint[i]]) continue;
add_edge(Belong[outpoint[i]],Belong[inpoint[i]],val[Belong[inpoint[i]]]);//重新建图
degree[Belong[inpoint[i]]]++;
}
topsort();//拓补排序
return 0;
}