• Codeforces 1129 E.Legendary Tree


    Codeforces 1129 E.Legendary Tree

    解题思路

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

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

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

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

    那么对于当前做到的序列的第 (x) 个位置,可以二分一个位置 (mid) ,询问 ((S={1},T={a_1dots 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
    ", (int) S.size());
    	for(int i = 0; i < (int) S.size(); i++) 
    		printf("%d ", S[i]);
    	printf("
    %d
    ", (int) T.size());
    	for(int i = 0; i < (int) T.size(); i++) 
    		printf("%d ", T[i]);
    	printf("
    %d
    ", 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
    ", Edge[i].first, Edge[i].second);
    	fflush(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Java Web Start应用管理
    搭建java开发环境需要什么软件,怎么搭建java开发环境?
    制作WinPE
    今天看见.do网页,疑惑,这是什么文件??又是什么新技术??查了一下
    VC用ADO访问数据库全攻略
    ASP连接11种数据库语法总结
    asp.net里导出excel表方法汇总
    ASP.NET 发邮件方法
    ASP.NET 网站开发日常异常总汇(持续更新)
    javascript操作JSON
  • 原文地址:https://www.cnblogs.com/mangoyang/p/10436264.html
Copyright © 2020-2023  润新知