Submission #526872

#TimeUsernameProblemLanguageResultExecution timeMemory
526872KoDAncient Books (IOI17_books)C++17
50 / 100
1204 ms152676 KiB
#include <bits/stdc++.h>
#include "books.h"

using std::vector;
using std::array;
using std::pair;
using std::tuple;

using ll = long long;

struct UnionFind {
	vector<int> par;
	UnionFind(const int n) : par(n, -1) {}
	int find(const int u) {
		return par[u] < 0 ? u : par[u] = find(par[u]);
	}
	void merge(int u, int v) {
		u = find(u), v = find(v);
		if (u == v) return;
		if (par[u] > par[v]) std::swap(u, v);
		par[u] += par[v];
		par[v] = u;
		return;
	}
};

ll minimum_walk(vector<int> P, int src) {
	{
		int l = 0;
		while (l < src and P[l] == l) l += 1;
		int r = (int)P.size() - 1;
		while (r > src and P[r] == r) r -= 1;
		P.erase(P.begin() + r + 1, P.end());
		P.erase(P.begin(), P.begin() + l);
		for (auto& x : P) x -= l;
		src -= l;
	}
	const int N = P.size();
	vector<vector<int>> cycle;
	{
		vector<char> done(N);
		for (int i = 0; i < N; ++i) {
			if (done[i]) continue;
			auto& v = cycle.emplace_back();
			for (int j = i; !done[j]; j = P[j]) {
				v.push_back(j);
				done[j] = true;
			}
		}
	}
	const int M = cycle.size();
	UnionFind dsu(M);
	{
		vector<vector<int>> list(2 * N);
		const auto process = [&](int k, const int i) {
			while (k > 0) {
				for (const int j : list[k]) dsu.merge(i, j);
				list[k] = {i};
				k >>= 1;
			}
		};
		for (int i = 0; i < M; ++i) {
			auto& v = cycle[i];
			std::sort(v.begin(), v.end());
			for (int j = 1; j < (int)v.size(); ++j) {
				const int lc = N + v[j - 1];
				const int rc = N + v[j];
				for (int l = lc, r = rc; l < r; l >>= 1, r >>= 1) {
					if (l & 1) list[l++].push_back(i);
					if (r & 1) list[--r].push_back(i);
				}
				process(lc, i);
				process(rc, i);
			}
		}
	}
	vector<int> belongs(N);
	for (int i = 0; i < M; ++i) {
		const int p = dsu.find(i);
		for (const int j : cycle[i]) {
			belongs[j] = p;
		}
	}
	vector<vector<int>> list(M);
	for (int i = 0; i < N; ++i) list[belongs[i]].push_back(i);
	vector<int> parent(M, -1);
	{
		vector<int> start(N, -1), end(N, -1);
		for (int j = 0; j < M; ++j) {
			if (!list[j].empty()) {
				start[list[j].front()] = j;
				end[list[j].back()] = j;
			}
		}
		vector<int> stack;
		for (int i = 0; i < N; ++i) {
			if (start[i] != -1) {
				if (!stack.empty()) parent[start[i]] = stack.back();
				stack.push_back(start[i]);
			}
			if (end[i] != -1) stack.pop_back();
		}
	}
	vector<int> dist(M, N + 1);
	{
		std::queue<int> que;
		const auto push = [&](const int u, const int d) {
			if (dist[u] > d) {
				dist[u] = d;
				que.push(u);
			}
		};
		push(belongs[src], 0);
		while (!que.empty()) {
			const int u = que.front();
			que.pop();
			const int l = list[u].front();
			const int r = list[u].back();
			if (l > 0) push(belongs[l - 1], dist[u] + 1);
			if (r + 1 < N) push(belongs[r + 1], dist[u] + 1);
		}
	}
	int root = belongs[src];
	while (parent[root] != -1) root = parent[root];
	ll ret = 2 * dist[root];
	vector<int> coeff(N);
	for (int i = 0; i < N; ++i) {
		const int l = std::min(i, P[i]);	
		const int r = std::max(i, P[i]);	
		ret += r - l;
		coeff[l] += 1;
		coeff[r] -= 1;
	}
	for (int i = 0; i < N - 1; ++i) {
		if (coeff[i] == 0) ret += 2;
		coeff[i + 1] += coeff[i];
	}
	return ret;
}
#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...