Codeforces 1900E Transitive Graph

发布时间 2023-12-23 14:10:55作者: rizynvu

考虑题目的限制条件:存在 $a\to b, b\to c$ 的边,就会有 $a\to c$ 的边。
考虑 $p_{1\sim k}$,满足这 $k$ 个点按顺序组成了一个环且无重点。
那么 $p_1\to p_2, p_2\to p_3$,就有 $p_1\to p_3$,又有 $p_3\to p_4$,所以有 $p_1\to p_4$。以此类推,会发现 $\forall i, j\in [1, k], i\not = j$,都存在 $i\to j, j\to i$。
那么就说明 $\forall i, j\in [1, k], i\not = j$,都存在 $i\to j$ 且能走完这 $k$ 个点且不重的路径。

于是考虑缩点,接下来图变成 $\text{DAG}$,就可以在 $\text{DAG}$ 上跑对应的拓扑。

但是有个问题,有没有可能存在 $a\to b\to c$ 的边,但需要把 $b$ 所在的强连通分量走完导致回不了 $b$ 就走不了了。
容易发现是不会的,首先若 $b$ 所在的强连通分量里只有 $b$ 显然满足。
否则随意从 $b$ 所在的强连通分量里找出一个点 $d(d\not = b)$,因为存在 $b\to d$,所以就存在 $d\to c$,这时候就可以扩展为 $a\to b\to d\to c$,同时前面提到了强连通分量里肯定存在 $b\to d$ 且能走完强连通分量里所有点且不重的路径,所以不会存在问题。

时间复杂度 $O(n + m)$。

#include<bits/stdc++.h>
using i64 = long long;
const int limn = 2e5, maxn = limn + 10;
std::vector<int> E[maxn], G[maxn];
i64 w[maxn], sum[maxn];
int dfn[maxn], low[maxn], dt, fa[maxn], ft, stk[maxn], top, ins[maxn], siz[maxn];
void dfs(int u) {
	dfn[u] = low[u] = ++dt, stk[++top] = u, ins[u] = 1;
	for (int v : E[u]) ! dfn[v] ? (dfs(v), low[u] = std::min(low[u], low[v]), 1) : (low[u] = std::min(low[u], ins[v] ? dfn[v] : low[u]), 1);
	if (low[u] != dfn[u]) return ;
	G[++ft].clear(), siz[ft] = 0, sum[ft] = 0;
	do {fa[stk[top]] = ft, ins[stk[top]] = 0, siz[ft]++, sum[ft] += w[stk[top]];} while (stk[top--] != u);
}
int mx[maxn], deg[maxn]; i64 mn[maxn];
auto solve = []() {
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) scanf("%lld", &w[i]);
	for (int i = 1; i <= n; i++) E[i].clear();
	for (int i = 1; i <= m; i++) {
		int x, y; scanf("%d%d", &x, &y);
		E[x].push_back(y);
	}
	for (int i = 1; i <= n; i++) dfn[i] = 0;
	dt = ft = 0;
	for (int i = 1; i <= n; i++) ! dfn[i] && (dfs(i), 1);
	for (int u = 1; u <= n; u++) for (int v : E[u])
		fa[u] != fa[v] && (G[fa[u]].push_back(fa[v]), deg[fa[v]]++, 1);
	static std::queue<int> q;
	for (int i = 1; i <= ft; i++) mx[i] = 0, mn[i] = 0;
	for (int i = 1; i <= ft; i++) ! deg[i] && (q.push(i), 1);
	while (! q.empty()) {
		int u = q.front(); q.pop();
		mx[u] += siz[u], mn[u] += sum[u];
		for (int v : G[u]) {
			(mx[u] > mx[v] || (mx[u] == mx[v] && mn[u] < mn[v])) && (mx[v] = mx[u], mn[v] = mn[u], 1);
			! (--deg[v]) && (q.push(v), 1);
		}
	}
	int id = 1;
	for (int i = 2; i <= ft; i++) (mx[i] > mx[id] || (mx[i] == mx[id] && mn[i] < mn[id])) && (id = i, 1);
	printf("%d %lld\n", mx[id], mn[id]);
};
int main() {
	int T; scanf("%d", &T);
	while (T--) solve();
	return 0;
}