P3387 【模板】缩点

求 DAG 中一条最大点权链

用 scc 缩点完成后其实问题就回到了 DAG,这样一个问题,开始 dfs 写多了,直接找入度为 0 为起点一个 dfs,结果就搜爆了。

正解:
寻找 DAG 中一个拓扑排序,按照拓扑序遍历点,再遍历点的边,dp 维护答案

而 Tarjan 缩点完成后新点的倒序(ans_scc -> 1)就是一个拓扑序,于是就不用再一遍拓扑了

点击查看代码
// Created by qyy on 2024/5/11.

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define PII pair<int, int>
#define endl "\n"

const long long inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int n, m, val[N], val_new[N], ans[N];


int head[N], cnt;
struct Edge{
    int from, to, nxt;
}e[N << 1];
void add(int u, int v){
    e[++cnt].from = u;
    e[cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

Edge e2[N];
int cnt2, head2[N];
void add2(int u, int v){
    e2[++cnt2].from = u;
    e2[cnt2].to = v;
    e2[cnt2].nxt = head2[u];
    head2[u] = cnt2;
}

int ans_scc, sccno[N], dfn[N], back[N], tim;
stack<int> st;
void dfs(int u){
    st.push(u);
    dfn[u] = back[u] = ++tim;
    for(int i = head[u]; i != 0; i = e[i].nxt){
        int v = e[i].to;
        if(!dfn[v]){
            dfs(v);
            back[u] = min(back[u], back[v]);
        }else if(!sccno[v]){
//            back[u] = min(back[u], dfn[v]);
            back[u] = min(back[u], back[v]);
        }
    }
    if(back[u] == dfn[u]){
        ans_scc++;
        while(1){
            int v = st.top();
            st.pop();
            sccno[v] = ans_scc;
            if(u == v) break;
        }
    }
}

void Tarjan(int n){
    ans_scc = tim = 0;
    memset(sccno, 0, sizeof(sccno));
    memset(dfn, 0, sizeof(dfn));
    memset(back, 0, sizeof(back));
    for(int i = 1; i <= n; i++){
        if(!dfn[i])
            dfs(i);
    }
}

void solve() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        cin >> val[i];
    }
    for(int i = 1; i <= m; i++){
        int u, v;
        cin >> u >> v;
        add(u, v);
    }
    Tarjan(n);

    for(int i = 1; i <= n; i++){
        val_new[sccno[i]] += val[i];
    }
    for(int i = 1; i <= cnt; i++){
        int u = e[i].from, v = e[i].to;
        if(sccno[u] != sccno[v]){
            add2(sccno[u], sccno[v]);
        }
    }
    vector<int> root;
    for(int i = 1; i <= ans_scc; i++){
        ans[i] = val_new[i];
    }
    for(int i = ans_scc; i >= 1; i--){
        for(int j = head2[i]; j != 0; j = e2[j].nxt){
            int v = e2[j].to;
            ans[v] = max(ans[v], ans[i] + val_new[v]);
        }
    }
    int res = 0;
    for(int i = 1; i <= ans_scc; i++){
        res = max(res, ans[i]);
    }
    cout << res << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

posted @ 2024-05-11 17:54  9102700  阅读(31)  评论(0)    收藏  举报