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;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10512584.html