传送门

 

题意:给你一个有向图,找寻一条路径使得经过的权值和最大(点可以重复经过,但是权值只加一次,点上的权值可加可不加)。

思路:用tanjar缩点将图转化为DAG,在tanjar缩点过程中记录一个强连通分量中正权值和,然后再跑一边记忆化dfs即可。

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=998424353;
const double INF=1e15;
const int maxn=1e5+5;

int n,m;
int value[30005];

struct node
{
    int e;
    int p;
}load[150005];
int sign,head[30005];

vector<int>p[30005];
int dp[30005];

int cnt,top,time;
int dfn[30005],low[30005];
int stack_[30005],instack[30005],belong[30005];

int sum[30005];

void add_edge(int s,int e)
{
    load[++sign]=node{e,head[s]};
    head[s]=sign;
}

void init()
{
    time=cnt=top=sign=0;
    for(int i=0;i<=n;i++)
    {
        dfn[i]=low[i]=sum[i]=instack[i]=0;
        head[i]=-1;
        dp[i]=-1;
        p[i].clear();
    }
}

void tanjar(int s)
{
    dfn[s]=low[s]=++time;
    instack[s]=1;
    stack_[++top]=s;
    for(int i=head[s];i!=-1;i=load[i].p)
    {
        int e=load[i].e;
        if(!dfn[e])
        {
            tanjar(e);
            low[s]=min(low[s],low[e]);
        }
        else
        {
            if(instack[e])
                low[s]=min(low[s],dfn[e]);
        }
    }
    int t;
    if(dfn[s]==low[s])
    {
        cnt++;
        do
        {
            t=stack_[top--];
            instack[t]=0;
            belong[t]=cnt;
            if(value[t]>0)///只取正值
                sum[cnt]+=value[t];
        }while(t!=s);
    }
}

int dfs(int s)
{
    if(dp[s]!=-1)
        return dp[s];
    dp[s]=sum[s];
    int d=p[s].size(),e;
    for(int i=0;i<d;i++)
    {
        e=p[s][i];
        dp[s]=max(dp[s],dp[e]+sum[s]);
    }
    return dp[s];
}

int main()
{
    int s,e;
    while(~scanf("%d %d",&n,&m))
    {
        init();
        for(int i=0;i<n;i++)
            scanf("%d",&value[i]);
        while(m--)
        {
            scanf("%d %d",&s,&e);
            add_edge(s,e);
        }
        for(int i=0;i<n;i++)
        {
            if(!dfn[i])
                tanjar(i);
        }
        ///将缩点后的图重新建边
        for(int i=0;i<n;i++)
        {
            for(int j=head[i];j!=-1;j=load[j].p)
            {
                e=load[j].e;
                if(belong[i]!=belong[e])
                    p[belong[i]].push_back(belong[e]);
            }
        }
        int ans=0;
        for(int i=1;i<=cnt;i++)
            ans=max(ans,dfs(i));
        printf("%d\n",ans);
    }
    return 0;
}