• CF1129E Legendary Tree 构造


    传送门


    神树可还行

    我们令(1)为树根,那么如果要询问(x)是否在(y)子树中,就令(S = {1} , T = {x} , u = y),询问一下就可以知道了。

    那么考虑先构造出一个这样的序列(a_i):对于树上的每一个节点(u),它的父亲在这个序列上的位置在它的前面。

    考虑增量构造。假如说我们已经构造出了(1)(i)的序列,现在要把(i+1)插入。有一种显然正确的构造方法:在序列上二分,找到一个最大的位置(p)满足(S = {1} , T = {a_1,a_2,...,a_p} , u = i+1)时询问答案为(0),将这个数放在(a_p)之后即可。

    接下来我们可以找边了。对于每一个点,我们找它的所有儿子,而它的儿子一定在序列的后面的位置。于是在(a_i)上从右往左扫,用一个vector维护当前未找到父亲的点的集合(P)。对于点(i),先询问(S = {1} , T = P , u = a_i)时是否存在答案,如果不存在直接退出,否则二分出在(P)中最靠前的儿子(P_j),连上边((i,P_j)),然后再对于(P' = {P_{j+1},P_{j+2},...,P_{|P|}})做这样的操作就可以了。

    复杂度:构造序列需要(nlogn)、每一个儿子被找到需要(nlogn)、每一个点失败的询问总共(n)次,加起来(2nlogn+n)可以通过本题。

    #include<iostream>
    #include<cstdio>
    #include<vector>
    //This code is written by Itst
    using namespace std;
    
    #define PII pair < int , int >
    int N;
    vector < PII > Edge;
    vector < int > S , T , arr , son;
    
    bool query(int u){
    	cout << S.size() << endl;
    	for(auto t : S) cout << t << ' ';
    	cout << endl << T.size() << endl;
    	for(auto t : T) cout << t << ' ';
    	cout << endl << u << endl;
    	int x; cin >> x; return x;
    }
    
    void answer(){
    	cout << "ANSWER" << endl;
    	for(auto t : Edge) cout << t.first << ' ' << t.second << endl;
    }
    
    int main(){
    	ios::sync_with_stdio(0);
    	cin >> N;
    	S.push_back(1);	arr.push_back(2);
    	for(int i = 3 ; i <= N ; ++i){
    		int L = 0 , R = i - 2;
    		while(L < R){
    			int mid = (L + R + 1) >> 1;
    			T.clear(); T.insert(T.begin() , arr.begin() , arr.begin() + mid);
    			query(i) ? R = mid - 1 : L = mid;
    		}
    		arr.insert(arr.begin() + L , i);
    	}
    	son.push_back(*--arr.end());
    	auto it = --arr.end();
    	while(it-- != arr.begin()){
    		auto t = son.begin();
    		while(t != son.end()){
    			T.clear(); T.insert(T.begin() , t , son.end());
    			if(!query(*it)) break;
    			int L = 0 , R = son.end() - t - 1;
    			while(L < R){
    				int mid = (L + R) >> 1;
    				T.clear(); T.insert(T.begin() , t , t + mid + 1);
    				query(*it) ? R = mid : L = mid + 1;
    			}
    			while(L){++t; --L;}
    			auto t1 = t; Edge.push_back(PII(*it , *t)); son.erase(t1);
    		}
    		son.push_back(*it);
    	}
    	for(auto t : son) Edge.push_back(PII(t , 1));
    	answer();
    	return 0;
    }
    
  • 相关阅读:
    AVUE 根据 某个字段 倒序查询
    Java hutool工具包的使用
    AVUE 添加搜索项
    SpringBlade 添加 回收站功能
    接口 form-data 将对象转换为复杂url参数
    AVUE 隐藏 新增按钮
    AVUE 查看crud列的属性配置
    AVUE dialog对话框 去掉 点击屏幕空白区 就关闭弹框
    接口 C#/Java 请求数据 raw 的方式传输复杂对象
    接口 PostMan 常用
  • 原文地址:https://www.cnblogs.com/Itst/p/10512584.html
Copyright © 2020-2023  润新知