【LOJ3274】「JOISC 2020 Day2」變色龍之戀

題目鏈接

點擊打開鏈接

題目解法

考慮子任務 44 的解法。
令一隻變色龍 xx 和其性別不同的變色龍集合 SS 會面,得到結果 resres ,討論若干情況可得:
(1)(1) 、若 LLx=xL_{L_x}=x ,當且僅當 SS 集合中存在與 xx 顏色相同的變色龍, res<S+1res<|S|+1
(2)(2) 、否則,當且僅當 SS 集合中存在與 xx 顏色相同或與 xx 存在喜愛關係的變色龍, res<S+1res<|S|+1

因此,可以通過不超過 3Log2N+O(N)3Log_2N+O(N) 次操作確定與每一個 xx 有特殊關係的變色龍集合 SxS_x
Sx=1S_x=1 ,則可以直接確定與其同色的異性變色龍。
否則, SxS_x 必然爲 33 ,組織 xx 與其中的每兩個元素進行一次會面,會有恰好一次得到的答案爲 11 ,此時沒有參與會面的變色龍是 xx 喜歡的變色龍。由此,可以找出所有單向喜歡的關係,確定答案。

對於原題,難點在於如何分離二分圖兩側的點集。
但實際上,子任務 44 解法中的 SS 集合並不一定需要滿足所有變色龍都與 xx 性別不同,只需要滿足 SS 集合內不存在特殊關係。因此,對於新處理的某條變色龍 xx ,將已有的特殊關係建出二分圖,並染色,對 xx 和二分圖兩側的變色龍集合都進行子任務 44 中的過程,即可找到新增的特殊關係。

時間複雜度 O(N2LogN)O(N^2LogN) ,操作次數不超過 3Log2N+O(N)3Log_2N+O(N)

#include "chameleon.h"
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 5;
const int Limit = 15000;
bool vis[MAXN];
bool col[MAXN];
int n, cnt, p[MAXN];
vector <int> a[MAXN];
vector <int> b[MAXN];
int ask(vector <int> a) {
	cnt++;
	return Query(a);
}
int ask(vector <int> a, int x) {
	a.push_back(x), cnt++;
	return Query(a);
}
void erase(vector <int> &a, int x) {
	for (unsigned i = 0; i < a.size(); i++)
		if (a[i] == x) {
			swap(a[i], a[a.size() - 1]);
			a.pop_back();
			return;
		}
}
void findedge(vector <int> st, int pos) {
	for (auto x : a[pos])
		erase(st, x);
	while (ask(st, pos) != st.size() + 1) {
		vector <int> now = st;
		while (now.size() != 1) {
			vector <int> a, b;
			for (unsigned i = 0; i < now.size(); i++)
				if (i & 1) a.push_back(now[i]);
				else b.push_back(now[i]);
			if (ask(a, pos) == a.size() + 1) now = b;
			else now = a;
		}
		int tmp = now.back();
		a[pos].push_back(tmp);
		a[tmp].push_back(pos);
		erase(st, tmp);
	}
}
void dfs(int pos, bool type) {
	col[pos] = type;
	vis[pos] = true;
	for (auto x : a[pos])
		if (!vis[x]) dfs(x, !type);
}
void Solve(int N) {
	n = N;
	for (int i = 1; i <= n * 2; i++) {
		memset(vis, false, sizeof(vis));
		for (int j = 1; j <= i - 1; j++)
			if (!vis[j]) dfs(j, true);
		vector <int> st;
		for (int j = 1; j <= i - 1; j++)
			if (col[j]) st.push_back(j);
		if (st.size() != 0) findedge(st, i);
		st.clear();
		for (int j = 1; j <= i - 1; j++)
			if (!col[j]) st.push_back(j);
		if (st.size() != 0) findedge(st, i);
	}
	for (int i = 1; i <= n * 2; i++)
		assert(a[i].size() == 1 || a[i].size() == 3);
	for (int i = 1; i <= n * 2; i++)
		if (a[i].size() == 3) {
			int x = 0;
			if (ask({i, a[i][0], a[i][1]}) == 1) assert(x == 0), x = a[i][2];
			if (ask({i, a[i][0], a[i][2]}) == 1) assert(x == 0), x = a[i][1];
			if (ask({i, a[i][1], a[i][2]}) == 1) assert(x == 0), x = a[i][0];
			assert(x != 0);
			b[i].push_back(x);
			b[x].push_back(i);
		}
	memset(vis, false, sizeof(vis));
	for (int i = 1; i <= n * 2; i++) {
		for (auto x : b[i])
			erase(a[i], x);
		assert(a[i].size() == 1);
		if (vis[i]) continue;
		int res = a[i].back();
		Answer(i, res);
		vis[i] = vis[res] = true;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章