题目链接


\(Description\)

有一棵\(n\)个点的树。你需要在\(11111\)次询问内确定出这棵树的形态。每次询问你给定两个非空且不相交的点集\(S,T\)和一个点\(u\),交互库会告诉你满足\(x\in S,y\in T\),且\(x\to y\)经过了\(u\)的点对\((x,y)\)的数量。

\(n\leq500\)。

\(Solution\)

不妨假设以\(1\)为根。首先如果想知道\(y\)是否在\(x\)的子树内,询问\(S=\{1\},T=\{y\},u=x\)就可以了(同样可以扩展到某点集中有多少个点在\(x\)子树内)。

那么对于每个点\(i\),询问\(S=\{1\},T=\{2,3,...,n\},u=i\),就可以知道\(i\)子树的大小\(size_i\)。

有什么用呢。。把所有点按\(size_i\)从大到小排序,那么该序列中每个点的父节点一定在它的左边。

(PS:这个序列还可以增量构造出来:考虑在已有\(1...i\)的序列中加入\(i+1\),二分找到一个最靠右的点\(p\),满足\(a_1,a_2,...,a_p\)没有点在\(i+1\)的子树中,然后把\(i+1\)插入到\(a_p\)后面即可。需要\(O(n\log n)\)次询问。)

考虑从右往左扫这个序列,对每个节点找出它直属的儿子。

假设当前是点\(i\),设\(i\)后面还没有找到父亲的点集是\(P\)。首先查一次\(P\)中是否没有点在\(i\)的子树中。\(S=\{1\},T=P,u=i\)询问一次即可。

若\(P\)中存在\(i\)子树内的点,可以二分找出\(P\)中最靠左的一个\(i\)的儿子\(P_j\),连边\((i,p)\)。然后再对\(P'=\{P_{j+1},P_{j+2},...\}\)继续重复上边过程即可。

询问次数\(O(n\log n)+2n\)。(数据实测最多\(<5500\))(有\(200\)组数据=-=)


#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#define pc putchar
#define Flush() fflush(stdout)
#define gc() getchar()
typedef long long LL;
const int N=505; int id[N],sz[N],fa[N]; inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now*f;
}
inline bool cmp(int a,int b)
{
return sz[a]>sz[b];
}
int Query_Size(int x,int n)
{
printf("1\n1\n%d\n",n-1);
for(int i=2; i<=n; ++i) printf("%d ",i);
return printf("\n%d\n",x),Flush(),read();
}
int Query_Exist(int x,const std::vector<int> &vec,int r)//vec中存在x子树中的点
{
printf("1\n1\n%d\n",r);
for(int i=0; i<r; ++i) printf("%d ",vec[i]);
return printf("\n%d\n",x),Flush(),read();
} int main()
{
const int n=read();
for(int i=1; i<=n; ++i) id[i]=i;
sz[1]=n;
for(int i=2; i<=n; ++i) sz[i]=Query_Size(i,n);
std::sort(id+1,id+1+n,cmp);
std::vector<int> vec;
for(int i=n; i; --i)
{
int x=id[i];
std::vector<int> P=vec,tmp;
while(!P.empty()&&Query_Exist(x,P,P.size()))
{
int l=1,r=P.size(),mid;
while(l<r)
if(Query_Exist(x,P,mid=l+r>>1)) r=mid;
else l=mid+1;
fa[P[--l]]=x;
auto it=P.begin();
while(l--) tmp.push_back(*it++);
P.erase(P.begin(),++it);
}
for(auto v:P) tmp.push_back(v);
vec=tmp, vec.push_back(x);
}
puts("ANSWER");
for(int i=2; i<=n; ++i) printf("%d %d\n",fa[i],i); return 0;
}

Codeforces.1129E.Legendary Tree(交互 二分)的更多相关文章

  1. Codeforces 1129E - Legendary Tree(思维题)

    Codeforces 题面传送门 & 洛谷题面传送门 考虑以 \(1\) 为根,记 \(siz_i\) 为 \(i\) 子树的大小,那么可以通过询问 \(S=\{2,3,\cdots,n\}, ...

  2. Codeforces.714D.Searching Rectangles(交互 二分)

    题目链接 \(Description\) 在一个\(n*n\)的二维平面中有两个不相交的整点矩形,每次可以询问两个矩形有几个完全在你给出的一个矩形中.200次询问内确定两个矩形坐标. \(Soluti ...

  3. Codeforces 1129 E.Legendary Tree

    Codeforces 1129 E.Legendary Tree 解题思路: 这题好厉害,我来复读一下官方题解,顺便补充几句. 首先,可以通过询问 \(n-1​\) 次 \((S=\{1\},T=\{ ...

  4. Problem - D - Codeforces Fix a Tree

    Problem - D - Codeforces  Fix a Tree 看完第一名的代码,顿然醒悟... 我可以把所有单独的点全部当成线,那么只有线和环. 如果全是线的话,直接线的条数-1,便是操作 ...

  5. Codeforces Round #381 (Div. 2) D. Alyona and a tree 树上二分+前缀和思想

    题目链接: http://codeforces.com/contest/740/problem/D D. Alyona and a tree time limit per test2 secondsm ...

  6. Codeforces E. Alyona and a tree(二分树上差分)

    题目描述: Alyona and a tree time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  7. Codeforces Round #381 (Div. 2)D. Alyona and a tree(树+二分+dfs)

    D. Alyona and a tree Problem Description: Alyona has a tree with n vertices. The root of the tree is ...

  8. Codeforces.862D.Mahmoud and Ehab and the binary string(交互 二分)

    题目链接 \(Description\) 有一个长为\(n\)的二进制串,保证\(01\)都存在.你可以询问不超过\(15\)次,每次询问你给出一个长为\(n\)的二进制串,交互库会返回你的串和目标串 ...

  9. Codeforces.810D.Glad to see you!(交互 二分)

    题目链接 \(Description\) 有一个大小为\(k\)的集合\(S\),元素两两不同且在\([1,n]\)内.你可以询问不超过\(60\)次,每次询问你给出\(x,y\),交互库会返回\(\ ...

随机推荐

  1. hibernate自定义校验Valid

    步骤: 1.定义注解: import javax.validation.Constraint; import javax.validation.Payload; import java.lang.an ...

  2. 【ShaderToy】抗锯齿相关函数

    *示例代码可以直接在ShaderToy中运行. *我放在这里咯ShaderToy基础学习中~欢迎交流(ノ>ω<)ノ 先上未抗锯齿的两个圆形图案,可以清楚看清图案边缘像素块,即“锯齿”. 附 ...

  3. 使用hql动态创建对象问题

    前段时间由于需求要添加报表数据,调整ireport后,打印pdf文件出现数据错位的情况,调试发现不是ireport问题,就查看了后台传送的数据,最后发现传送的对象属性值已经就是错位的,那就是获取对象时 ...

  4. Linux基础命令(三)——>文件过滤及内容编辑处理命令

    1.cat   合并文件或查看文件内容 基本功能:cat   test.txt     查看文件内容 也可以多文件显示 cat  test1.txt test2.txt >test3.txt   ...

  5. ARIMA模型原理

    一.时间序列分析 北京每年每个月旅客的人数,上海飞往北京每年的游客人数等类似这种顾客数.访问量.股价等都是时间序列数据.这些数据会随着时间变化而变化.时间序列数据的特点是数据会随时间的变化而变化. 随 ...

  6. 查看提交历史(git log)

    git log 命令 在完成了几次提交,或者克隆了一个已有提交历史的仓库后,要查看历史提交记录,可以通过git log命令来实现. $ git log commit 0becea8e1966df258 ...

  7. Laravel框架中打印sql

     在使用Laravel框架的时候,调试的时候,需要将查询的SQL输出校验,这是需要将SQL打印出来. 一.方法 DB::connection()->enableQueryLog();  // 开 ...

  8. django在windows下的经历

    django-admin.py startproject project_name 去掉.py 常见命令:https://blog.csdn.net/weixin_42134789/article/d ...

  9. hibernate之一级缓存

    缓存目的:提高效率. sql语句与数据库交互,返回数据组装成对象存入session缓存中.程序查询时,优先访问缓存中是否存在id相同对象. hibernate中session缓存(一级缓存)存在

  10. PHP程序运行性能分析

    php在使用了xdebug后,可以配置xdebug相关的配置,生成运行的日志. 在php.ini中配置: xdebug.profiler_enable = 1 xdebug.profiler_enab ...