P3387 【模板】缩点
先tarjan 缩点,然后重构图,用map消除重复边,之后记忆化搜索,reutrn maxx;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
typedef std :: pair<int,int> PII;
const int N = 1e5+9;
struct node
{
int from,to;
}edge[N];
int idx,e[N],ne[N],w[N],h[N],w2[N];
int dfn[N],low[N];
int timestamp;
int stk[N];
int vis[N];
int id[N],scc_cnt;
bool in_stk[N];
int top;
int out[N];
int n,m;
int dp[N];
PII st[N];
std :: map<PII,int> mp;
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++timestamp;
stk[++top] = u,in_stk[u] = true;
for(int i=h[u]; ~i; i=ne[i])
{
int j = e[i];
if(!dfn[j])
{
tarjan(j);
low[u] = std :: min(low[u],low[j]);
}
else if(in_stk[j])
{
low[u] = std :: min(low[u],dfn[j]);
}
}
if(dfn[u] == low[u])
{
++scc_cnt;
int y;
do
{
y = stk[top--];
in_stk[y] = false;
id[y] = scc_cnt;
}
while(y != u);
}
}
int dfs(int u)
{
if(~dp[u]) return dp[u];
dp[u] = w[u];
int maxx = 0;
for(int i=h[u]; ~i; i=ne[i])
{
int j = e[i];
maxx = std :: max(maxx,dfs(j));
dp[u] = maxx;
}
return dp[u] = maxx + w[u];
}
int main()
{
memset(h,-1,sizeof h);
memset(dp,-1,sizeof dp);
std :: cin >> n >> m;
for(int i=1; i<=n; i++) std :: cin >> w[i];
for(int i=1; i<=m; i++)
{
int a,b;
std :: cin >> a >> b;
edge[i].from = a,edge[i].to = b;
add(a,b);
}
for(int i=1; i<=n; i++)
{
if(!dfn[i]) tarjan(i);
}
for(int i=1; i<=n; i++)
{
w2[id[i]] += w[i];
}
for(int i=1; i<=n; i++) w[i] = w2[i];
memset(h,-1,sizeof h);
memset(dp,-1,sizeof dp);
idx = 0;
for(int i=1; i<=m; i++)
{
int a = edge[i].from,b = edge[i].to;
if(id[a] == id[b] || mp[{id[a],id[b]}]) continue;
mp[{id[a],id[b]}] = 1;
add(id[a],id[b]);
}
int ans = 0;
for(int i=1; i<=scc_cnt; i++)
{
if(!vis[i]) ans = std :: max(ans,dfs(i));
}
std :: cout<<ans<<"\n";
return 0;
}