Codeforces 1129 E.Legendary Tree

Codeforces 1129 E.Legendary Tree

解题思路

这题好厉害,我来复读一下官方题解,顺便补充几句。

首先,可以通过询问 \(n-1​\)\((S=\{1\},T=\{2\dots n\},i),i\in[2,n]​\) ,来得到以 \(1​\) 为根树的所有节点的子树大小。

然后考虑从子树大小最小的节点开始,为每一个节点找它们的儿子,由于每个节点儿子的子树大小,一定小于这个节点的子树大小,所以可以按照子树大小从小到大排序,每个节点的儿子就一定在其前面。

假设已经找到了一个节点的儿子,那么考虑把这个节点当前找到的这个儿子在序列中删除,对于序列中在其后面的那个节点来说,其前面除了它的儿子以为所有点都不在它的子树中。

那么对于当前做到的序列的第 \(x\) 个位置,可以二分一个位置 \(mid\) ,询问 \((S=\{1\},T=\{a_1\dots a_{mid}\},x)\) ,第一个返回结果不是 \(0\)\(mid\) 一定 \(x\) 的儿子,这样重复做下去直到还原总询问次数是 \(O(n-1+(n-1)logn)\)

code

/*program by mangoyang*/
#pragma GCC optimize("inline", "Ofast")
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
	int ch = 0, f = 0; x = 0;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
	for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
	if(f) x = -x;
}
const int N = 1005;
vector<int> S, T;
vector<pair<int, int> > Edge;
int sz[N], a[N], del[N], n;
inline int query(vector<int> S, vector<int> T, int x){
	printf("%d\n", (int) S.size());
	for(int i = 0; i < (int) S.size(); i++) 
		printf("%d ", S[i]);
	printf("\n%d\n", (int) T.size());
	for(int i = 0; i < (int) T.size(); i++) 
		printf("%d ", T[i]);
	printf("\n%d\n", x);
	fflush(stdout);
	int ans = 0;
	return read(ans), ans;
}
inline bool cmp_size(int x, int y){
	return sz[x] < sz[y];
}
inline int check(int mid, int x){
	T.clear();
	for(int i = 1; i <= mid; i++) 
		if(!del[i]) T.push_back(a[i]);
	if(!(int)T.size()) return 0;
	return query(S, T, x) > 0;
}
int main(){
	read(n);
	S.push_back(1);
	for(int i = 2; i <= n; i++) T.push_back(i);
	sz[1] = n;
	for(int i = 2; i <= n; i++)
		sz[i] = query(S, T, i);
	for(int i = 1; i <= n; i++) a[i] = i;
	sort(a + 1, a + n + 1, cmp_size);
	for(int i = 1; i < n; i++){
		int u = a[i];
		if(sz[u] == 1) continue;
		while(1){
			int l = 1, r = i - 1, pos = -1;
			while(l <= r){
				int mid = (l + r) >> 1;
				if(check(mid, u)) pos = mid, r = mid - 1;
				else l = mid + 1;
			}
			if(pos == -1) break;
			del[pos] = 1;
			Edge.push_back(make_pair(u, a[pos]));
		}
	}
	for(int i = 1; i < n; i++) 
		if(!del[i]) Edge.push_back(make_pair(a[i], 1));
	puts("ANSWER");
	for(int i = 0; i < (int) Edge.size(); i++)
		printf("%d %d\n", Edge[i].first, Edge[i].second);
	fflush(stdout);
	return 0;
}
posted @ 2019-02-26 11:38  Joyemang33  阅读(233)  评论(0编辑  收藏  举报