题目
终于会写交互了
粗略观察一下,发现这道题树的部分查询次数要求是\(O(n\log n)\)级别,链部分要求是\(O(n)\)级别而且要求这个常数比较小
先来考虑链怎么搞,我们可以随机一个序列,之后按照顺序explore
这些点,如果一个点已经被探明了,我们就跳过它;我们维护当前已经扩展出来的这条链的左右端点,每次遇到一个未探明点时,就用这左右两个端点分别explore
一下,看看这个点在哪个端点的下面,之后一直搞下去,直到这个点被探明为止,之后再将这个点设为新的端点。
不难发现这样每个点最多会被explore
两次,这询问次数好像有点超的样子;但是我们随机了序列,这相当于对链的两边做随机分治,于是询问次数是期望\(n+\log n\)的。
再来考虑树的情况,一个直观的想法是分治,设当前的根为\(x\),我们把\(x\)子树内部的点跟\(x\)explore
一遍,之后按照得到的结果把他们分到不同的子树中去;这样的询问次数是\(\sum_{i=1}^ndep_i\),又能过完全二叉树的subtask了。
这个询问次数太垃圾了,我们需要做的是将每个点的询问次数优化到\(\log n\);
假如我们现在有一棵点分树,如果我们要探明一个点\(x\),我们就explore
一下当前分治重心与\(x\);我们把得到的结果一路暴跳,这样就能知道下一层的分治重心是谁,之后继续到下一层的分治重心去询问,直到\(x\)被探明,之后再把\(x\)加入点分树。
这样探明\(x\)的询问次数是点分树的树高次,时间复杂度是点分树树高的平方次,于是只要我们能保证点分树\(\log\)的树高,就能解决这个问题了。于是是我们只需要一个替罪羊重构就好了。
这样询问次数是\(O(n\log n)\)的,时间复杂度是\(O(n\log^2 n)\)的
代码
#include
#include "rts.h"
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
const int maxn=3e5+5;
int c[maxn],p[maxn];
std::vector d[maxn];
void dfs(int x,int fa,int n) {
for(re int i=2;i<=n;i++) {
if(c[i]) continue;
int v=explore(x,i);
if(c[v]) continue;
c[v]=1;dfs(v,x,n);
}
}
void divide(int x) {
int rt[2];rt[0]=rt[1]=0;
for(re int i=0;i