제출 #600003

#제출 시각아이디문제언어결과실행 시간메모리
600003jophyyjhSplit the Attractions (IOI19_split)C++14
40 / 100
108 ms16076 KiB
/**
 * [S1-3]	First 3 subtasks are pretty straight-forward. [S1] is either a cycle or
 * 		a chain, which is simple. For [S2] we can just find a spanning tree and pick
 * 		a random leaf node for set A. [S3] is just a DFS on tree, which means find
 * 		a spanning tree + DFS scores 40. Don't have much thoughts on [S4-5].
 * 
 * Time Complexity: O(n + m * log(m))
 * Implementation 1		(only solves S1-3)
*/

#include <bits/stdc++.h>
#include "split.h"

typedef std::vector<int>	vec;

vec parent, rank;

inline int find(int k) {
	if (parent[k] == k)
		return k;
	return parent[k] = find(parent[k]);
}

bool merge(int a, int b) {
	a = find(a), b = find(b);
	if (a == b)
		return false;
	if (rank[b] > rank[a])
		std::swap(a, b);
	parent[b] = a, rank[a] += rank[b];
	return true;
}


struct set_t {
	int size, original_idx;
};

std::vector<vec> tree;
vec subtree;

void find_subsize(int k, int parent) {
	subtree[k] = 1;
	for (int child : tree[k]) {
		if (child == parent)
			continue;
		find_subsize(child, k);
		subtree[k] += subtree[child];
	}
}

vec find_split(int n, int a, int b, int c, vec p, vec q) {
	int m = p.size();
	std::vector<set_t> sizes(3);
	sizes[0].size = a, sizes[1].size = b, sizes[2].size = c;
	for (int i = 0; i < 3; i++)
		sizes[i].original_idx = i + 1;
	std::sort(sizes.begin(), sizes.end(),
			  [](const set_t& s1, const set_t& s2) {
			      return s1.size < s2.size;
			  });
	
	parent.resize(n);
	rank.resize(n);
	for (int i = 0; i < n; i++)
		parent[i] = i, rank[i] = 1;
	std::vector<bool> tree_edge(m, false);
	tree.assign(n, vec());
	subtree.resize(n);
	for (int k = 0; k < m; k++) {
		if (merge(p[k], q[k])) {
			tree[p[k]].emplace_back(q[k]);
			tree[q[k]].emplace_back(p[k]);
		} else {
			tree_edge[k] = true;
		}
	}
	find_subsize(0, -1);

	int node1 = -1, node2 = -1;
	bool found = false;
	for (int k = 0; k < m && !found; k++) {
		if (tree_edge[k])
			continue;
		node1 = p[k], node2 = q[k];
		if (subtree[node1] > subtree[node2])
			std::swap(node1, node2);
		int size1 = subtree[node1], size2 = n - size1;
		if (size1 > size2) {
			std::swap(size1, size2);
			std::swap(node1, node2);
		}
		if (size1 >= sizes[0].size && size2 >= sizes[1].size)
			found = true;
	}
	if (!found)
		return vec(n, 0);
	std::cerr << node1 << ": " << sizes[0].size << ", " << node2 << ": " << sizes[1].size << std::endl;
	vec ans(n, 2);
	std::vector<bool> visited(n, false);
	visited[node1] = visited[node2] = true;
	std::queue<int> bfs_queue;
	bfs_queue.emplace(node1);
	for (int _ = 0; _ < sizes[0].size; _++) {
		assert(!bfs_queue.empty());
		int t = bfs_queue.front();
		bfs_queue.pop();
		ans[t] = 0;
		for (int neighb : tree[t]) {
			if (visited[neighb])
				continue;
			visited[neighb] = true;
			bfs_queue.emplace(neighb);
		}
	}
	bfs_queue = std::queue<int>();
	bfs_queue.emplace(node2);
	for (int _ = 0; _ < sizes[1].size; _++) {
		assert(!bfs_queue.empty());
		int t = bfs_queue.front();
		bfs_queue.pop();
		ans[t] = 1;
		for (int neighb : tree[t]) {
			if (visited[neighb])
				continue;
			visited[neighb] = true;
			bfs_queue.emplace(neighb);
		}
	}
	for (int i = 0; i < n; i++)
		ans[i] = sizes[ans[i]].original_idx;	// convert back to (1,2,3) - (A,B,C)
	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...