CF1900E Transitive Graph 题解

考虑原图如果存在一条从 aabb 的路径,那么新图中 aa 会向路径上每一个点连边,证明显然。

进一步的,一个强连通分量内部在新图上必然是完全图。

考虑缩点,然后直接朴素 DP 即可,每个 SCC 内每个点都可以走,SCC 之间只能按照 DAG 的走法走。fuf_ugug_u 分别表示从这个 SCC 出发的最长路径长度以及在满足长度最长的情况下的最小权值。容易转移。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
using namespace std;

const int N = 2e5 + 5;

int scc_idx;
int t, n, m;
vector<int> G[N], RG[N], NG[N];
bool vis[N];
int a[N];
long long f[N], f2[N];
int cnt[N];
long long sum[N];
vector<int> ver;
int bel[N];

void dfs(int u)
{
	vis[u] = 1;
	for (auto& j : G[u])
	{
		if (!vis[j]) dfs(j);
	}
	ver.emplace_back(u);
}

void rdfs(int u)
{
	cnt[scc_idx]++;
	vis[u] = 1;
	sum[scc_idx] += a[u];
	bel[u] = scc_idx;
	for (auto& j : RG[u])
	{
		if (!vis[j]) rdfs(j);
	}
}

void kosaraju()
{
	for (int i = 1; i <= n; i++)
	{
		if (!vis[i]) dfs(i);
	}
	for (int i = 1; i <= n; i++) vis[i] = 0;
	for (int i = n - 1; i >= 0; i--)
	{
		if (!vis[ver[i]])
		{
			scc_idx++;
			rdfs(ver[i]);
		}
	}
}

void dfs_dag(int u)
{
	if (f[u]) return;
	f[u] = cnt[u];
	if (!NG[u].size())
	{
		f2[u] = sum[u];
		return;
	}
	for (auto& j : NG[u])
	{
		dfs_dag(j);
		if (f[j] + cnt[u] > f[u])
		{
			f[u] = f[j] + cnt[u];
			f2[u] = f2[j] + sum[u];
		}
		else if (f[j] + cnt[u] == f[u])
		{
			if (f2[j] + sum[u] < f2[u]) f2[u] = f2[j] + sum[u];
		}
	}
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> t;
	while (t--)
	{
		ver.clear();
		cin >> n >> m;
		for (int i = 1; i <= n; i++) G[i].clear(), RG[i].clear(), vis[i] = 0;
		for (int i = 1; i <= n; i++) cin >> a[i];
		for (int i = 1; i <= scc_idx; i++) NG[i].clear(), f[i] = 0, f2[i] = (long long)4e18, cnt[i] = sum[i] = 0;
		scc_idx = 0;
		vector<pair<int, int>> egs;
		for (int i = 1; i <= m; i++)
		{
			int u, v;
			cin >> u >> v;
			egs.emplace_back(make_pair(u, v));
			G[u].emplace_back(v);
			RG[v].emplace_back(u);
		}
		kosaraju();
		for (auto& [u, v] : egs)
		{
			if (bel[u] ^ bel[v]) NG[bel[u]].emplace_back(bel[v]);
		}
		for (int i = 1; i <= scc_idx; i++)
		{
			if (!f[i])
			{
				dfs_dag(i);
			}
		}
		int maxd = 0;
		long long minn = (long long)4e18;
		for (int i = 1; i <= scc_idx; i++)
		{
			if (f[i] > maxd)
			{
				maxd = f[i];
				minn = f2[i];
			}
			else if (f[i] == maxd && f2[i] < minn) minn = f2[i];
		}
		cout << maxd << " " << minn << "\n";
	}
	return 0;
}
posted @   HappyBobb  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示