Submission #1155145

#TimeUsernameProblemLanguageResultExecution timeMemory
1155145tesseractDreaming (IOI13_dreaming)C++20
100 / 100
60 ms16016 KiB
#include "dreaming.h"
#include <compare>
#include <vector>
#include <ranges>
#include <algorithm>
#include <limits>
#include <functional>

#include <iostream>

using namespace std;

class VertexAndWeight {
public:
	int vertex;
	int weight;

	VertexAndWeight(int vertex_, int weight_) : weight(weight_), vertex(vertex_) {}

	weak_ordering operator<=>(const VertexAndWeight &other) const {
		return this->weight <=> other.weight;
	}

	VertexAndWeight plusWeight(int w) const {
		return {vertex, weight+w};
	}

	VertexAndWeight &maxEquals(const VertexAndWeight &other) {
		if(other > *this) {
			*this = other;
		}
		return *this;
	}

};

vector<vector<VertexAndWeight>> adjl;

const int NO_PARENT = -1;
// The parent of a given vertex, or NO_PARENT if there is no parent.
vector<int> parent;

vector<int> distFromRoot;

pair<int, int> processTreeAndGetRadiusDiameter(int v);

int travelTime(int N, int M, int L, int A[], int B[], int T[]) {
	adjl.resize(N);
	distFromRoot.resize(N);
	ranges::fill(distFromRoot, -1);

	parent.resize(N);
	ranges::fill(parent, NO_PARENT);
	for(int i : views::iota(0,M)) {
		adjl[A[i]].push_back({B[i], T[i]});
		adjl[B[i]].push_back({A[i], T[i]});
	}

	vector<int> forestRadii;
	vector<int> forestDiameters;
	//cerr << "N = " << N << endl;
	for(int v : views::iota(0,N)) {
		//cerr << v << "  A\n";
		if(distFromRoot[v] == -1) { // has not been included in any tree yet
			auto [r, d] = processTreeAndGetRadiusDiameter(v);
			//cerr << v << " " << r << " " << d << "  B\n";
			forestRadii.push_back(r);
			forestDiameters.push_back(d);
		}
	}
	if(forestDiameters.size() == 1) {
		return forestDiameters[0];
	} else if (forestDiameters.size() == 2) {
		// Connect the centroids of the two trees in the forest by an edge.
		return max({forestDiameters[0], forestDiameters[1], forestRadii[0] + L + forestRadii[1]});
	} else {
		// Connect the centroid of the tree with the largest radius
		// to each of the centroids of the other trees.

		partial_sort(forestRadii.begin(), forestRadii.begin()+3, forestRadii.end(), greater<int>());
		return max({
			*max_element(forestDiameters.begin(), forestDiameters.end()),
			forestRadii[0] + L + forestRadii[1],
			forestRadii[1] + 2*L + forestRadii[2]
		});
	}
}

VertexAndWeight getFarthestVertexAndWeight(int v, int par, int dRoot);

pair<int, int> processTreeAndGetRadiusDiameter(int v) {
	//cerr << "Starting tree " << v << endl;

	int d1 = getFarthestVertexAndWeight(v, NO_PARENT, 0).vertex;

	//cerr << "Intermediate tree " << v << endl;
	auto [d2, diameter] = getFarthestVertexAndWeight(d1, NO_PARENT, 0);

	int x = d2;
	int radius = numeric_limits<int>::max();
	while(x != NO_PARENT) { // each x is a potential centroid
		radius = min(radius, max(distFromRoot[x], diameter - distFromRoot[x]));
		x = parent[x];
	}

	//cerr << "Ending tree " << v << " " << radius << " " << diameter << endl;
	return {radius, diameter};
}

// Implements DFS
VertexAndWeight getFarthestVertexAndWeight(int v, int par, int dRoot) {
	//cerr << "   DFS " << v << endl;
	parent[v] = par;
	distFromRoot[v] = dRoot;
	VertexAndWeight ans(v, 0);

	for(auto child : adjl[v]) if (child.vertex != parent[v]) {
		VertexAndWeight farthestForThisChild =
			getFarthestVertexAndWeight(child.vertex, v, dRoot + child.weight);

		ans.maxEquals(farthestForThisChild.plusWeight(child.weight));
	}
	return ans;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...