【模板】Tarjan scc缩点

代码如下

#include <bits/stdc++.h>

using namespace std;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1);
	vector<vector<int>> adj(n + 1);
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= m; i++) {
		int u, v;
		cin >> u >> v;
		adj[u].push_back(v);
	}	
	vector<int> dfn(n + 1), low(n + 1), scc(n + 1);
	vector<vector<int>> has(1);
	int dfn_cnt = 0, scc_cnt = 0;
	stack<int> st;
	function<void(int)> tarjan = [&](int u) {
		dfn[u] = low[u] = ++dfn_cnt;
		st.push(u);
		for (int v : adj[u]) {
			if (dfn[v] == 0) {
				tarjan(v);
				low[u] = min(low[u], low[v]);
			} else if (scc[v] == 0) {
				low[u] = min(low[u], dfn[v]);
			}
		}
		if (low[u] == dfn[u]) {
			++scc_cnt;
			has.push_back(vector<int>());
			while (1) {
				int v = st.top();
				st.pop();
				scc[v] = scc_cnt;
				has[scc_cnt].push_back(v);
				if (v == u) {
					break;
				} 
			}
		}
	};
	for (int i = 1; i <= n; i++) {
		if (dfn[i] == 0) {
			tarjan(i);
		}
	}
	vector<vector<int>> g(scc_cnt + 1);
	vector<int> degree(scc_cnt + 1), b(scc_cnt + 1);
	for (int i = 1; i <= scc_cnt; i++) {
		for (auto x : has[i]) {
			b[i] += a[x];
		}
	}
	for (int u = 1; u <= n; u++) {
		for (auto v : adj[u]) {
			if (scc[u] != scc[v]) {
				g[scc[u]].push_back(scc[v]);
				++degree[scc[v]];
			}
		}
	}
	queue<int> q;
	vector<int> f(scc_cnt + 1);
	for (int i = 1; i <= scc_cnt; i++) {
		if (degree[i] == 0) {
			q.push(i);
		}
	}
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		f[u] += b[u];
		for (auto v : g[u]) {
			f[v] = max(f[v], f[u]);
			if (--degree[v] == 0) {
				q.push(v);
			}
		}
	}
	cout << *max_element(f.begin(), f.end()) << endl;
	return 0;
} 
posted @ 2019-03-16 23:04  shellpicker  阅读(206)  评论(0编辑  收藏  举报