• CF1129E Legendary Tree 题解


    Codeforces
    Luogu

    Description.

    交互,有一棵大小为 \(n\) 的树。
    每次询问 \(S,T,u(S\cap T=\varnothing)\),返回 \(\sum_{x\in S}\sum_{y\in T}[u\in\text{path}(x,y)]\)
    \(n\le 500,\text{limit}\le 11111\)

    Solution.

    就首先确定一个点的 \(siz\),可以问 \(S=\{1\},T=\{2,3,...,n\},u=x\) 得到。
    然后按照 \(siz\) 排序,接下来相当于要找到它的父亲,不是很能做。
    确定一个点儿子是可以做的,就问 \(1\)\([l,r]\) 是否有经过 \(x\) 的边就行了。
    不断二分,每次找到最靠左的一个儿子,然后直接删掉。
    每个点的儿子总数是 \(O(n)\) 的,所以总复杂度 \(O(n\log n)\)
    交互次数限制很松。

    Coding.

    点击查看代码
    //Coded by Kamiyama_Shiki on 2021.11.14 {{{
    //是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    const int N=505;
    int n,sz[N],id[N],fa[N];vector<int>v;
    inline void makef(int it,int f)
    {
    	fa[v[it]]=f;for(int i=it;i<(int)v.size()-1;i++) v[i]=v[i+1];
    	v.pop_back();
    }
    inline int findps(int x) {for(int i=0;i<(int)v.size();i++) if(v[i]==x) return i;return -1;}
    inline int getps(int l,int r,int fa)
    {
    	if(l>r) return -1;
    	printf("1\n1\n%d\n",r-l+1);int cnt=0,vl,md=(l+r)>>1;
    	for(int j=l;j<=r;j++) printf("%d%c",v[j],j==r?'\n':' ');
    	printf("%d\n",fa),fflush(stdout),read(cnt);if(!cnt) return -1;
    	if(l==r) return l;else if(~(vl=getps(l,md,fa))) return vl;else return getps(md+1,r,fa);
    }
    int main()
    {
    	read(n),sz[1]=n,id[1]=1;
    	for(int i=2;i<=n;i++)
    	{
    		printf("1\n1\n%d\n",n-1);
    		for(int j=2;j<=n;j++) printf("%d%c",j,j==n?'\n':' ');
    		printf("%d\n",i),fflush(stdout),read(sz[i]),id[i]=i;
    	}
    	sort(id+1,id+n+1,[&](int a,int b) {return sz[a]>sz[b];});
    	for(int i=2;i<=n;i++) v.push_back(id[i]);
    	for(int z=n-1,i=id[z],vl;z>=1;i=id[--z]) while(1)
    		if(~(vl=getps(findps(i)+1,v.size()-1,i))) makef(vl,i);else break;
    	puts("ANSWER");for(int i=2;i<=n;i++) printf("%d %d\n",fa[i],i);
    	return 0;
    }
    
  • 相关阅读:
    Linux shellcode sample
    Linux Shell Bash 带有特殊含义的退出码
    编写 Bash 补全脚本
    《什么是数学》读书笔记(一):反证法、数学归纳法与唯一分解定理
    令人称奇的简单证明:五种方法证明根号2是无理数
    2017 Multi-University Training Contest
    2017 Multi-University Training Contest
    2017 Multi-University Training Contest
    2017 Multi-University Training Contest
    51 Nod 1008 N的阶乘 mod P【Java大数乱搞】
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15554382.html
Copyright © 2020-2023  润新知