缩点,将该有向有环图变为有向无环图,然后dp求解

因为已经变为有向无环图,所以其中号强连通分量的儿子


首先用Kosaraju找强连通分量,第一遍dfs遍历,并从后往前压入dfn栈中,然后再FILO进行第二遍dfs,对于每次遍历到的点均构成一个强连通分量。

然后用set容器储存各个强连通分量的边,用dp求解

const int N = 2e4;
int n, m, a[N], mark[N], t[N];
vi rim[N], nrim[N], dfn;
bitset<10086> vis;
set<int> s[N];
LL dp[N];

void dfs(int x)
{
    vis[x] = 1;
    for (auto it : rim[x])
    {
        if (!vis[it])
            dfs(it);
    }
    dfn.pb(x);
}
int cnt;
void dfs1(int x)
{
    mark[x] = cnt, t[cnt] += a[x];
    //cout<<a[x]<<"jkj\n";
    for (auto it : nrim[x])
    {
        if (!mark[it])
            dfs1(it);
    }
}
inline void df(int x)
{
    if(dp[x])
    return ;
    for(auto it:s[x]){
        df(it);
        dp[x]=max(dp[x],dp[it]);
    }
    dp[x]+=t[x];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    f(i, 1, n) cin >> a[i];
    f(i, 1, m)
    {
        int x, y;
        cin >> x >> y;
        rim[x].pb(y);
        nrim[y].pb(x);
    }
    vis.reset();
    f(i, 1, n)
    {
        if (!vis[i])
            dfs(i);
    }
    vis.reset();
    for (auto it = dfn.rbegin(); it != dfn.rend(); it++)
    {
        if (!mark[*it])
        {
            cnt+=1;
            dfs1(*it);
        }
    }
    f(i, 1, n)
    {
        for (auto it : rim[i])
        {
            if (mark[i] != mark[it])
                s[mark[i]].insert(mark[it]);
        }
    }
    LL ans = 0;
    f(i, 1, cnt )
    {
        df(i);
        ans = max(ans, dp[i]);
    }
    cout << ans;
    return 0;
}
此文章已被阅读次数:正在加载...更新于