1 条题解

  • 0
    @ 2025-8-24 23:06:40

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Lele_Programmer
    Ad Astra Per Aspera || F1 车迷 || Love Miku

    搬运于2025-08-24 23:06:40,当前版本为作者最后更新于2024-12-15 18:47:13,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P11354 题解

    交互题好玩。

    思路

    询问次数最多为 3535,不难想到二分。

    也就是说,每一次询问,都要砍掉半棵树。

    对于一棵树,由根节点出发,往更大的子树走,直到子树大小不超过原来一整棵树的大小的 12\frac{1}{2},返回该节点。这样一来,在子树大小大于整棵树大小的 12\frac{1}{2} 时,会不断地缩小子树大小,逼近总大小的 12\frac{1}{2}

    考虑最坏情况,当某棵子树大小为总大小的 12\frac{1}{2} 多一个点时,若它的子树大小平分,那么每一次最少会砍掉 14\frac{1}{4} 的大小。

    由此可得平均询问次数为 O(log2n)\mathcal{O}(\log_2 n)最坏询问次数为 O(log43n)\mathcal{O}(\log_{\frac{4}{3}} n),最坏会询问到 4040 次。可是呢,感觉造不出这样的数据,因为每次操作都会对整棵树的大小发生变化。能过就行了吧。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define endl '\n'
    #define FRR(file) freopen(file,"r",stdin)
    #define FRW(file) freopen(file,"w",stdout)
    #define TIMESTAMP cerr<<fixed<<setprecision(3)<<clock()*1.0/CLOCKS_PER_SEC<<"s"<<endl;
    #define _rep(i,a,b) for (int i=(a);i<=(b);++i)
    #define _reps(i,a,b,c) for (int i=(a);i<=(b);c)
    #define _rrep(i,a,b) for (int i=(a);i>=(b);--i)
    #define _rreps(i,a,b,c) for (int i=(a);i>=(b);c)
    #define _iter(i,a) for (auto i=a.begin();i!=a.end();++i)
    #define _graph(i,u) for (int i=h[u];~i;i=ne[i])
    #define rint register int
    #define LL long long
    typedef pair<int,int> pii;
    
    const int N=100005;
    
    int n,root;
    int sz[N];
    bool flag[N];
    vector<int> vec[N];
    
    extern "C" bool ask(int k);
    
    inline void dfs(int u) {
        if (flag[u]) {
            sz[u]=0;
            return;
        }
        sz[u]=1;
        _iter(it,vec[u]) {
            dfs(*it);
            sz[u]+=sz[*it];
        }
    }
    
    inline int find(int u) {
        if (sz[u]<=sz[root]/2) return u;
        assert(!vec[u].empty());
        if (vec[u].size()==2 && sz[vec[u][0]]<sz[vec[u][1]]) swap(vec[u][0],vec[u][1]);
        return find(vec[u][0]);
    }
    
    extern "C" int solve(int n,vector<int> p) {
        // assert(ask(1)==1);
        _rep(i,0,(int)p.size()-1) vec[p[i]].emplace_back(i+2);
        root=1;
        while (true) {
            dfs(root);
            if (sz[root]==1) return root;
            int t=find(root);
            int k=ask(t);
            if (k) root=t;
            else flag[t]=true;
        }
        return 114514;
    }
    
    • 1

    信息

    ID
    9539
    时间
    2000ms
    内存
    512MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者