Submission #1205293

#TimeUsernameProblemLanguageResultExecution timeMemory
1205293SzilSimurgh (IOI17_simurgh)C++20
100 / 100
1010 ms6484 KiB
#include "simurgh.h"
#include <bits/stdc++.h>

using namespace std;

struct dsu {
	vector<int> par;

	dsu(int n) {
		par.resize(n);
		iota(par.begin(), par.end(), 0);
	}

	int holvan(int u) {
		return par[u] == u ? u : (par[u] = holvan(par[u]));
	}

	bool unio(int u, int v) {
		u = holvan(u); v = holvan(v);
		if (u == v) return 0;
		par[u] = v;
		return 1;
	}
};

vector<int> find_roads(int n, vector<int> e1, vector<int> e2) {
	int m = e1.size();
	vector<vector<pair<int, int>>> g(n), g2(n);
	vector<int> dfs_tree;
	vector<int> col(n);
	vector<bool> vis(n);
	for (int i = 0; i < m; i++) {
		g[e1[i]].emplace_back(e2[i], i);
		g[e2[i]].emplace_back(e1[i], i);
	}
	auto dfs = [&](auto &&self, int u) -> void {
		vis[u] = 1;
		for (auto [v, idx] : g[u]) {
			if (vis[v]) continue;
			dfs_tree.emplace_back(idx);
			g2[u].emplace_back(v, idx);
			g2[v].emplace_back(u, idx);
			self(self, v);
		}
	};
	dfs(dfs, 0);
	auto dfs2 = [&](auto &&self, int u, int block, int c) -> void {
		col[u] = c;
		for (auto [v, idx] : g2[u]) {
			if (col[v] || v == block) continue;
			self(self, v, block, c);
		}
	};

	int asked = 0;
	int dfs_tree_cnt = count_common_roads(dfs_tree);
	asked++;
	vector<int> label(m, -1);
	for (int idx : dfs_tree) {
		int u = e1[idx];
		int v = e2[idx];
		fill(col.begin(), col.end(), 0);
		dfs2(dfs2, u, v, 1);
		dfs2(dfs2, v, u, 2);
		vector<int> replacements;
		for (int i = 0; i < m; i++) {
			if (i == idx) continue;
			if (col[e1[i]] != col[e2[i]]) {
				replacements.emplace_back(i);
			}
		}
		if (replacements.empty()) {
			label[idx] = 1;
			continue;
		}
		vector<int> s;
		for (int x : dfs_tree) {
			if (x != idx) s.emplace_back(x);
		}
		bool ok = false;
		for (int x : replacements) {
			if (label[x] != -1) {
				s.emplace_back(x);
				ok = true;
				assert(asked <= 8000);
				int cnt = count_common_roads(s);
				asked++;
				int should_be = dfs_tree_cnt + (label[x] == 1);
				label[idx] = should_be != cnt;
				break;
			}
		}

		if (ok) continue;
		
		label[idx] = 1;
		int it = 0;
		vector<int> checked;
		for (int x : replacements) {
			it++;
			s.emplace_back(x);
			assert(asked <= 8000);
			int cnt = count_common_roads(s);
			asked++;
			if (cnt > dfs_tree_cnt) {
				label[idx] = 0;
				break;
			}
			if (cnt < dfs_tree_cnt) {
				break;
			}
			checked.emplace_back(x);
			s.pop_back();
		}
		for (int x : checked) {
			label[x] = label[idx];
		}
	}

	vector<int> todo;
	vector<int> vis2(n), vis3(m);
	
	auto gen_todo = [&](auto &&self, int u) -> void {
		vis2[u] = 1;
		for (auto [v, idx] : g[u]) {
			if (label[idx] != -1 || vis2[v] || vis3[idx]) continue;
			vis3[idx] = 1;
			todo.emplace_back(idx);
			self(self, v);
		}
	};
	for (int it = 0; it < 500; it++) {
		fill(vis2.begin(), vis2.end(), 0);
		for (int i = 0; i < n; i++) {
			if (!vis2[i]) gen_todo(gen_todo, i);
		}
	}

	auto f = [&](int l, int r) {
		dsu ds(n);
		vector<int> roads;
		for (int i = l; i < r; i++) {
			ds.unio(e1[todo[i]], e2[todo[i]]);
			roads.emplace_back(todo[i]);
		}
		int should_be = dfs_tree_cnt;
		for (int idx : dfs_tree) {
			if (!ds.unio(e1[idx], e2[idx])) {
				should_be -= label[idx];
			} else {
				roads.emplace_back(idx);
			}
		}
		int cnt = count_common_roads(roads);
		asked++;
		return cnt > should_be;
	};

	int nxt = 0;
	while (nxt < todo.size()) {
		int last = nxt;
		dsu ds(n);
		while (last < todo.size()) {
			if (ds.unio(e1[todo[last]], e2[todo[last]])) {
				last++;
			} else {
				break;
			}
		}
		if (!f(nxt, last)) {
			nxt = last;
			continue;
		}
		int lo = nxt, hi = last-1;
		while (lo < hi) {
			int mid = (lo + hi + 1) / 2;
			if (!f(nxt, mid)) lo = mid;
			else hi = mid-1;
		}
		nxt = lo+1;
		label[todo[lo]] = 1;
	}

	vector<int> ans;
	for (int i = 0; i < m; i++) {
		if (label[i] == 1) ans.emplace_back(i);
	}
	
	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...