洛谷P4742 [Wind Festival]Running In The Sky(Tarjan强联通缩点+记忆化搜索)

题目链接: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 '\n'
#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\n",ans1,ans2);
}
View Code

 

posted @ 2020-07-12 19:16  Anonytt  阅读(149)  评论(0)    收藏  举报