tkmst201's Library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub tkmst201/Library

:heavy_check_mark: Test/CentroidDecomposition.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/tree_diameter"

#include "GraphTheory/CentroidDecomposition.hpp"

#include <cstdio>
#include <vector>
#include <cassert>

std::pair<long long, std::vector<int>> tree_diameter(const std::vector<std::vector<std::pair<int, int>>> & wg) {
	assert(!wg.empty());
	using CD = CentroidDecomposition;
	using ll = long long;
	const int n = wg.size();
	CD::Graph g(n);
	for (int i = 0; i < n; ++i) {
		g[i].reserve(wg[i].size());
		for (const auto & e : wg[i]) {
			const int v = e.first;
			assert(0 <= v && v < n);
			g[i].emplace_back(v);
		}
	}
	CD cd(g);
	struct Data { ll dist; int u, v; };
	auto dfs = [&](auto self, int centroid) -> Data {
		cd.done(centroid);
		Data res{0, centroid, centroid};
		std::pair<ll, int> top[2];
		std::fill(top, top + 2, std::make_pair(0, centroid));
		for (const auto [v, d] : wg[centroid]) {
			if (!cd.exist(v)) continue;
			auto dfs2 = [&](auto self, int u, int p) -> std::pair<ll, int> {
				std::pair<ll, int> res{0, u};
				for (const auto & e : wg[u]) { // auto [v, d] internal compiler error

					const int v = e.first;
					const ll d = e.second;
					if (v == p || !cd.exist(v)) continue;
					auto [mxd, mxu] = self(self, v, u);
					if (res.first < mxd + d) res = {mxd + d, mxu};
				}
				return res;
			};
			auto pred = dfs2(dfs2, v, -1);
			pred.first += d;
			if (top[0] < pred) top[1] = std::move(top[0]), top[0] = pred;
			else if (top[1] < pred) top[1] = std::move(pred);
			auto pred2 = self(self, cd.centroids(g, v)[0]);
			if (res.dist < pred2.dist) res = pred2;
		}
		if (top[0].first + top[1].first > res.dist) return {top[0].first + top[1].first, top[0].second, top[1].second};
		return res;
	};
	Data dat = dfs(dfs, cd.centroids(g, 0)[0]);
	std::vector<int> par(n, -1);
	auto dfs3 = [&](auto self, int u) -> void {
		for (auto v : g[u]) if (v != par[u]) par[v] = u, self(self, v);
	};
	dfs3(dfs3, dat.u);
	std::vector<int> path;
	path.emplace_back(dat.v);
	while (par[path.back()] != -1) path.emplace_back(par[path.back()]);
	return {dat.dist, path};
}

int main() {
	int N;
	scanf("%d", &N);
	
	std::vector<std::vector<std::pair<int, int>>> g(N);
	for (int i = 0; i < N - 1; ++i) {
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		g[a].emplace_back(b, c);
		g[b].emplace_back(a, c);
	}
	
	auto [ans, path] = tree_diameter(g);
	printf("%lld %d\n", ans, (int)path.size());
	for (int i = 0; i < path.size(); ++i) printf("%d%c", path[i], " \n"[i + 1 == path.size()]);
}
#line 1 "Test/CentroidDecomposition.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/tree_diameter"

#line 1 "GraphTheory/CentroidDecomposition.hpp"



#include <vector>
#include <cassert>
#include <algorithm>

/**
 * @brief https://tkmst201.github.io/Library/GraphTheory/CentroidDecomposition.hpp
 */
struct CentroidDecomposition {
	using Graph = std::vector<std::vector<int>>;
	
private:
	int n;
	std::vector<bool> done_;
	std::vector<int> sz;
	
public:
	explicit CentroidDecomposition(const Graph & g) : n(g.size()), done_(size(), false), sz(size(), 0) {
		for (int i = 0; i < size(); ++i) for (int j : g[i]) assert(0 <= j && j < size());
	}
	
	int size() const noexcept {
		return n;
	}
	
	bool exist(int u) const noexcept {
		assert(0 <= u && u < size());
		return !done_[u];
	}
	
	std::vector<int> centroids(const Graph & g, int root) {
		assert(0 <= root && root < size());
		assert(exist(root));
		auto dfs = [&](auto self, int u, int p) -> void {
			sz[u] = 1;
			for (auto v : g[u]) if (v != p && exist(v)) self(self, v, u), sz[u] += sz[v];
		};
		dfs(dfs, root, -1);
		int u = root, p = -1;
		std::vector<int> res;
		while (true) {
			bool update = false;
			for (auto v : g[u]) {
				if (v == p || !exist(v)) continue;
				if (sz[v] * 2 > sz[root]) { p = u; u = v; update = true; break; }
				if (sz[v] * 2 == sz[root]) res.emplace_back(v);
			}
			if (update) continue;
			res.emplace_back(u);
			break;
		}
		return res;
	}
	
	void done(int v) noexcept {
		assert(0 <= v && v < size());
		done_[v] = true;
	}
	
	void clear() {
		std::fill(begin(done_), end(done_), false);
	}
};


#line 4 "Test/CentroidDecomposition.test.cpp"

#include <cstdio>
#line 8 "Test/CentroidDecomposition.test.cpp"

std::pair<long long, std::vector<int>> tree_diameter(const std::vector<std::vector<std::pair<int, int>>> & wg) {
	assert(!wg.empty());
	using CD = CentroidDecomposition;
	using ll = long long;
	const int n = wg.size();
	CD::Graph g(n);
	for (int i = 0; i < n; ++i) {
		g[i].reserve(wg[i].size());
		for (const auto & e : wg[i]) {
			const int v = e.first;
			assert(0 <= v && v < n);
			g[i].emplace_back(v);
		}
	}
	CD cd(g);
	struct Data { ll dist; int u, v; };
	auto dfs = [&](auto self, int centroid) -> Data {
		cd.done(centroid);
		Data res{0, centroid, centroid};
		std::pair<ll, int> top[2];
		std::fill(top, top + 2, std::make_pair(0, centroid));
		for (const auto [v, d] : wg[centroid]) {
			if (!cd.exist(v)) continue;
			auto dfs2 = [&](auto self, int u, int p) -> std::pair<ll, int> {
				std::pair<ll, int> res{0, u};
				for (const auto & e : wg[u]) { // auto [v, d] internal compiler error

					const int v = e.first;
					const ll d = e.second;
					if (v == p || !cd.exist(v)) continue;
					auto [mxd, mxu] = self(self, v, u);
					if (res.first < mxd + d) res = {mxd + d, mxu};
				}
				return res;
			};
			auto pred = dfs2(dfs2, v, -1);
			pred.first += d;
			if (top[0] < pred) top[1] = std::move(top[0]), top[0] = pred;
			else if (top[1] < pred) top[1] = std::move(pred);
			auto pred2 = self(self, cd.centroids(g, v)[0]);
			if (res.dist < pred2.dist) res = pred2;
		}
		if (top[0].first + top[1].first > res.dist) return {top[0].first + top[1].first, top[0].second, top[1].second};
		return res;
	};
	Data dat = dfs(dfs, cd.centroids(g, 0)[0]);
	std::vector<int> par(n, -1);
	auto dfs3 = [&](auto self, int u) -> void {
		for (auto v : g[u]) if (v != par[u]) par[v] = u, self(self, v);
	};
	dfs3(dfs3, dat.u);
	std::vector<int> path;
	path.emplace_back(dat.v);
	while (par[path.back()] != -1) path.emplace_back(par[path.back()]);
	return {dat.dist, path};
}

int main() {
	int N;
	scanf("%d", &N);
	
	std::vector<std::vector<std::pair<int, int>>> g(N);
	for (int i = 0; i < N - 1; ++i) {
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		g[a].emplace_back(b, c);
		g[b].emplace_back(a, c);
	}
	
	auto [ans, path] = tree_diameter(g);
	printf("%lld %d\n", ans, (int)path.size());
	for (int i = 0; i < path.size(); ++i) printf("%d%c", path[i], " \n"[i + 1 == path.size()]);
}
Back to top page