Cod sursa(job #1711354)

Utilizator tamionvTamio Vesa Nakajima tamionv Data 31 mai 2016 00:57:34
Problema Revolta Scor 0
Compilator cpp Status done
Runda Arhiva ICPC Marime 4.7 kb
#include <fstream>
#include <vector>
#include <stack>
#include <iostream>
#include <numeric>
#include <array>
#include <algorithm>
#include <functional>
using namespace std;

void dfs_tata(const int cur, const vector<vector<int>>& vec, vector<int>& tata){
	for(const auto next : vec[cur]){
		if(next != tata[cur]){
			tata[next] = cur;
			dfs_tata(next, vec, tata); } } }

void dfs_adanc(const int cur, const vector<vector<int>>& vec, vector<int>& adanc, const int prev = -1){
	for(const auto next : vec[cur]){
		if(next != prev){
			adanc[next] = adanc[cur] + 1;
			dfs_adanc(next, vec, adanc, cur); } } }

void dfs_euler(const int cur, const vector<vector<int>>& vec, vector<int>& euler, vector<int>& firsts, const int prev = -1){
	firsts[cur] = euler.size();
	for(const auto next : vec[cur]){
		if(next != prev){
			euler.push_back(cur);
			dfs_euler(next, vec, euler, firsts, cur); } }
	euler.push_back(cur); }

void reset_adanc_dfs(const int cur, const vector<vector<int>>& vec, vector<int>& adanc, const int prev = -1){
	adanc[cur] = -1;
	for(const auto next : vec[cur]){
		if(next != prev){
			reset_adanc_dfs(next, vec, adanc, cur); } } }

vector<int> find_path(const int x, const int y, const vector<vector<int>>& vec){
	vector<int> tata(vec.size(), -1);
	dfs_tata(x, vec, tata);
	vector<int> rez;
	for(int a = y; a != -1; a = tata[a]){
		rez.push_back(a); }
	reverse(begin(rez), end(rez));
	return rez; }

pair<int, int> find_diametru(const int rad, const vector<vector<int>>& vec, vector<int>& adanc){
	adanc[rad] = 0;
	dfs_adanc(rad, vec, adanc);
	const int c1 = max_element(begin(adanc), end(adanc)) - begin(adanc);

	adanc[c1] = 0;
	dfs_adanc(c1, vec, adanc);
	const int c2 = max_element(begin(adanc), end(adanc)) - begin(adanc);

	reset_adanc_dfs(rad, vec, adanc);

	return make_pair(c1, c2); }

static constexpr int maxniv = 20;

class rmq{
	int n;
	array<vector<int>, maxniv> buf;
public:
	rmq(const vector<int>& v): n(v.size()){
		for(auto& x : buf){
			x.resize(n); }
		for(int i = 0; i < n; ++i){
			buf[0][i] = v[i]; }
		for(int niv = 1, step = 1; niv < maxniv; ++niv, step *= 2){
			for(int i = 0, j = step; j < n; ++i, ++j){
				buf[niv][i] = min(buf[niv-1][i], buf[niv-1][j]); } } }
	void operator=(rmq&& rhs){
		n = rhs.n;
		for(int i = 0; i < maxniv; ++i){
			buf[i] = move(rhs.buf[i]); } }
	int operator()(const int x, const int y)const{
		const int len = y-x+1, niv = log2(len), step = 1<<niv;
		return min(buf[niv][x], buf[niv][y-step+1]); } };

class dist_finder{
	int n;
	vector<int> adanc;
	vector<int> pozs;
	rmq r;
public:
	dist_finder(const vector<vector<int>>& vec): n(vec.size()), adanc(n, 0), pozs(n, -1),
		r(vector<int>(0, 0)){

		vector<int> euler;

		dfs_adanc(0, vec, adanc);
		dfs_euler(0, vec, euler, pozs);
		for(auto& x : euler){
			x = adanc[x]; }

		r = rmq(euler); }
	int operator()(int a, int b)const{
		if(pozs[a] > pozs[b]){
			swap(a, b); }
		return adanc[a] + adanc[b] - 2*r(pozs[a], pozs[b]); } };

void do_test(ifstream& f, ofstream& g){
	int n;
	f >> n;

	vector<vector<int>> v(n);
	vector<int> dist(n, -1), tata(n, -1), euler;

	for(int i = 0, x, y; i < n-1; ++i){
		f >> x >> y;
		v[x].push_back(y);
		v[y].push_back(x); }

	const dist_finder df(v);

	const auto diam_ends = find_diametru(0, v, dist);
	const auto diam = find_path(diam_ends.first, diam_ends.second, v);
	const int diam_len = diam.size();

	auto erase_hf_muc = [&](const int x, const int y){
		v[x].erase(find(begin(v[x]), end(v[x]), y)); };

	for(int i = 0, j = 1; j < diam_len; ++i, ++j){
		erase_hf_muc(diam[i], diam[j]);
		erase_hf_muc(diam[j], diam[i]); }

	vector<pair<int, int>> diam_left(diam_len), diam_right(diam_len);

	auto cmp_diams = [&df](const pair<int, int>& a, const pair<int, int>& b){
		return df(a.first, a.second) < df(b.first, b.second); };
	auto merge_diams = [&](const pair<int, int>& a, const pair<int, int>& b){
		return max({a, b, make_pair(a.first, b.second), make_pair(a.second, b.first)}, cmp_diams); };

	for(int i = 0; i < diam_len; ++i){
		diam_left[i] = diam_right[i] = find_diametru(diam[i], v, dist); }

	partial_sum(begin(diam_left), end(diam_left), begin(diam_left), merge_diams);
	partial_sum(diam_right.rbegin(), diam_right.rend(), diam_right.rbegin(), merge_diams);

	vector<int> diam_len_left(diam_len), diam_len_right(diam_len);

	for(int i = 0; i < diam_len; ++i){
		diam_len_left[i] = df(diam_left[i].first, diam_left[i].second);
		diam_len_right[i] = df(diam_right[i].first, diam_right[i].second); }

	int rez = diam_len-1;
	for(int i = 0, j = 1; j < diam.size(); ++i, ++j){
		rez = min<int>(rez, ceil((double)diam_len_left[i] / 2.0) + ceil((double)diam_len_right[j] / 2.0) + 1); }

	g << rez << '\n'; }

int main(){
	ifstream f("revolta.in");
	ofstream g("revolta.out");

	int t;
	f >> t;

	for( ; t; --t){
		do_test(f, g); }

	return 0; }