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;
}

浙公网安备 33010602011771号