题目链接:https://www.luogu.com.cn/problem/P4742
思路:这个其实还是很简单的吧,为什么我会单独拿出来写一个博客呢?是因为这里的记忆化搜索在日后会对我有所启发吧。整体思路很简单:就是Tarjan强联通缩点后重建新图。然后在新图上跑dfs记忆化搜索。

#include<bits/stdc++.h> #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl ' ' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=5e5+5; int tot,head[maxn]; struct E{ int to,next; }edge[maxn<<1]; void add(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } int n,m,p[maxn]; int uu[maxn],vv[maxn]; int low[maxn],vis[maxn],dfn[maxn],id[maxn],Max[maxn],sum[maxn],tott,cnt; stack<int> s; void tarjan(int x){ dfn[x]=low[x]=++tott; s.push(x);vis[x]=1; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].to; if(!dfn[v]){ tarjan(v); low[x]=min(low[x],low[v]); } else if(vis[v]){ low[x]=min(low[x],dfn[v]); } } if(low[x]==dfn[x]){ ++cnt; while(1){ int now=s.top();s.pop(); id[now]=cnt; Max[cnt]=max(Max[cnt],p[now]); sum[cnt]+=p[now]; vis[now]=0; if(x==now) break; } } } int ans1,ans2; int f[maxn],ff[maxn]; void dfs(int x){ if(f[x]) return ; f[x]=sum[x]; ff[x]=Max[x]; int M1=0,M2=0; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].to; dfs(v); if(f[v]>M1) M1=f[v],M2=ff[v]; else if(f[v]==M1){ if(ff[v]>M2) M2=ff[v]; } } f[x]=f[x]+M1; ff[x]=max(ff[x],M2); } int main(){ scanf("%d%d",&n,&m);mem(head,-1);tott=cnt=0; ans1=ans2=0; rep(i,1,n) scanf("%d",&p[i]); rep(i,1,m){ scanf("%d%d",&uu[i],&vv[i]); add(uu[i],vv[i]); } rep(i,1,n){ if(!dfn[i]) tarjan(i); } mem(head,-1);tot=0; rep(i,1,m){ if(id[uu[i]]==id[vv[i]]) continue; add(id[uu[i]],id[vv[i]]); } rep(i,1,cnt){ if(!f[i]){ dfs(i); } if(f[i]>ans1) ans1=f[i],ans2=ff[i]; } printf("%d %d ",ans1,ans2); }