제출 #830075

#제출 시각아이디문제언어결과실행 시간메모리
830075PurpleCrayonSplit the Attractions (IOI19_split)C++17
100 / 100
138 ms33812 KiB
#include "split.h"
#include <bits/stdc++.h>
using namespace std;

#define sz(v) int(v.size())
#define ar array
typedef long long ll;
const int N = 2e5+10, MOD = 1e9+7;

struct DSU {
	vector<int> par, sz;
	DSU() {}
	DSU(int n): par(n) {
		iota(par.begin(), par.end(), 0);
		sz.assign(n, 1);
	}
 
	int find_set(int v) {
		return v == par[v] ? v : par[v] = find_set(par[v]);
	}
 
	bool union_sets(int a, int b) {
		if ((a = find_set(a)) == (b = find_set(b))) return false;
		if (sz[a] < sz[b]) swap(a, b);
		par[b] = a, sz[a] += sz[b], sz[b] = 0;
		return true;
	}
} d;
 

int n, m, sub[N], who[N];
vector<int> adj[N];
vector<int> tree[N], extra[N];
bool vis[N];

void dfs_tree(int c) {
	vis[c] = 1;
	for (int nxt : adj[c]) if (!vis[nxt]) {
		tree[c].push_back(nxt);
		tree[nxt].push_back(c);
		dfs_tree(nxt);
	}
}

int dfs_sub(int c, int p) {
	sub[c] = 1;
	for (int nxt : tree[c]) if (nxt != p) {
		sub[c] += dfs_sub(nxt, c);
	}
	return sub[c];
}

int dfs_cent(int c, int p) {
	for (int nxt : tree[c]) if (nxt != p && sub[nxt] > n / 2)
		return dfs_cent(nxt, c);

	return c;
}

void dfs_who(int c, int p, int cur) {
	who[c] = cur;
	for (int nxt : tree[c]) if (nxt != p) {
		dfs_who(nxt, c, cur);
	}
}

bool marked[N];
void dfs_mark(int c, int p) {
	marked[c] = 1;
	for (int nxt : tree[c]) if (nxt != p) {
		dfs_mark(nxt, c);
	}
}

vector<int> collect;
int sum = 0;

void dfs_collect(int c) {
	vis[c] = 1;
	if (sum > 0) {
		sum -= sub[c];
		collect.push_back(c);
	}

	for (int nxt : extra[c]) if (!vis[nxt]) {
		dfs_collect(nxt);
	}
}

vector<int> ord;
bool only[N], has[N];

void dfs_ord(int c) {
	has[c] = 1;
	ord.push_back(c);
	for (int nxt : adj[c]) if (!has[nxt] && only[nxt]) {
		dfs_ord(nxt);
	}
}

vector<int> trim(vector<int> nodes, int cnt) {
	memset(only, 0, sizeof(only));
	memset(has, 0, sizeof(has));
	for (int x : nodes) only[x] = 1;

	ord.clear();
	dfs_ord(nodes[0]);

	ord.resize(cnt);
	return ord;
}

vector<int> get_from_mark(const vector<pair<int, int>>& cols) {
	vector<int> one, two;
	for (int i = 0; i < n; i++) {
		if (marked[i]) one.push_back(i);
		else two.push_back(i);
	}

	one = trim(one, cols[0].first);
	two = trim(two, cols[1].first);

	vector<int> ans(n, cols[2].second);
	for (int x : one) ans[x] = cols[0].second;
	for (int x : two) ans[x] = cols[1].second;
	return ans;
}

vector<int> find_split(int _n, int p1, int p2, int p3, vector<int> p, vector<int> q) {
	n = _n, m = sz(p);
	for (int i = 0; i < m; i++) {
		int x = p[i], y = q[i];
		adj[x].push_back(y), adj[y].push_back(x);
	}

	vector<pair<int, int>> cols(3);
	cols[0] = {p1, 1}, cols[1] = {p2, 2}, cols[2] = {p3, 3};
	sort(cols.begin(), cols.end());

	dfs_tree(0);
	dfs_sub(0, -1);

	int root = dfs_cent(0, -1);
	dfs_sub(root, -1);
	who[root] = -1;
	for (int nxt : tree[root]) {
		dfs_who(nxt, root, nxt);
	}

	for (int nxt : tree[root]) {
		if (sub[nxt] >= cols[0].first) {
			dfs_mark(nxt, root);
			return get_from_mark(cols);
		}
	}

	for (int i = 0; i < m; i++) {
		if (who[p[i]] != who[q[i]] && who[p[i]] >= 0 && who[q[i]] >= 0) {
			extra[who[p[i]]].push_back(who[q[i]]);
			extra[who[q[i]]].push_back(who[p[i]]);
		}
	}

	memset(vis, 0, sizeof(vis));
	for (int nxt : tree[root]) if (!vis[nxt]) {
		collect.clear();
		sum = cols[0].first;

		dfs_collect(nxt);
		if (sum > 0) continue;

		for (int v : collect) dfs_mark(v, root);
		return get_from_mark(cols);
	}

	return vector<int>(n, 0);
}
#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...