传送门
先tarjan缩点。
方法1:然后在DAG上dp一下最长路即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
const int N=1e4+4,M=1e5+4;
int n,m;
vector<int > g[N],ng[N];
int dfn[N],low[N],bel[N],tim=0,snt=0,v[N],sum[N],dp[N];
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
stack<int > S;
void dfs(int p) {
low[p]=dfn[p]=++tim;
S.push(p);
for (int i=0;i<g[p].size();++i) {
int v=g[p][i];
if (!dfn[v]) {
dfs(v);
low[p]=min(low[p],low[v]);
}
else if (!bel[v]) low[p]=min(low[p],dfn[v]);
}
if (dfn[p]==low[p]) {
++snt;
while (1) {
int t=S.top();
S.pop();
bel[t]=snt;
sum[snt]+=v[t];
if (t==p) break;
}
}
}
int cal(int p) {
int &ret=dp[p],mx=0;
if (ret>0) return ret;
ret=sum[p];
for (int i=0;i<ng[p].size();++i)
mx=max(mx,cal(ng[p][i]));
return ret+=mx;
}
int main() {
// freopen("P3387.in","r",stdin);
memset(sum,0,sizeof(sum));
memset(dfn,0,sizeof(dfn));
n=read(),m=read();
for (register int i=1;i<=n;++i) v[i]=read();
for (register int i=0;i<m;++i) {
int u=read(),v=read();
g[u].push_back(v);
}
for (register int i=1;i<=n;++i)
if (!dfn[i]) dfs(i);
for (register int u=1;u<=n;++u)
for (int i=0;i<g[u].size();++i) {
int v=g[u][i];
if (bel[u]^bel[v])
ng[bel[u]].push_back(bel[v]);
}
int ret=-0x3f3f3f3f;
for (register int i=1;i<=snt;++i)
ret=max(ret,cal(i));
cout<<ret<<endl;
return 0;
}
方法2:然后统计入度为0的点,将它们push到队列中用SPFA跑多源最长路(!仅限于正权值的图,此题据透露数据无负数,所以此方案可行)
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e4+2,MAXM=1e5+2;
int n,m;
int head[MAXN],edge=0;
struct EDGE {
int v,nxt;
}e[MAXM];
int dfn[MAXN],low[MAXN],tim=0,snt=0,bel[MAXN];
bool ins[MAXN];
int val[MAXN],sum[MAXN],dp[MAXN];
stack<int> S;
vector<int> G[MAXN];
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void adde(int u,int v) {
e[edge].nxt=head[u],e[edge].v=v,head[u]=edge++;
}
void dfs(int p) {
S.push(p);
dfn[p]=low[p]=++tim;
ins[p]=true;
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (!dfn[v]) {
dfs(v);
low[p]=min(low[p],low[v]);
}
else if (ins[v]) low[p]=min(low[p],dfn[v]);
}
if (dfn[p]==low[p]) {
sum[++snt]=0;
while (!S.empty()) {
int t=S.top();
S.pop();
bel[t]=snt;
ins[t]=false;
sum[snt]+=val[t];
if (t==p) break;
}
}
}
int ind[MAXN],vis[MAXN];
queue<int> q;
inline int SPFA() {
while (!q.empty()) {
int p=q.front();
q.pop();
vis[p]=false;
for (int i=0;i<G[p].size();++i) {
int v=G[p][i];
if (dp[v]<dp[p]+sum[v]) {
dp[v]=dp[p]+sum[v];
if (!vis[v]) {
q.push(v);
vis[v]=true;
}
}
}
}
int res=0;
for (int i=1;i<=snt;++i)
res=max(res,dp[i]);
return res;
}
int main() {
memset(ind,0,sizeof(ind));
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(ins,false,sizeof(ins));
memset(vis,false,sizeof(vis));
n=read(),m=read();
for (register int i=1;i<=n;++i) val[i]=read(),G[i].clear();
for (register int i=1;i<=m;++i) {
int u=read(),v=read();
adde(u,v);
}
for (register int i=1;i<=n;++i)
if (!dfn[i]) dfs(i);
for (register int p=1;p<=n;++p) {
dp[p]=sum[p];
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (bel[p]^bel[v]) G[bel[p]].push_back(bel[v]),++ind[bel[v]];
}
}
for (int i=1;i<=snt;++i)
if (!ind[i]) q.push(i),vis[i]=true;
printf("%d\n",SPFA());
return 0;
}