终于会写交互了
粗略观察一下,发现这道题树的部分查询次数要求是(O(nlog 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(nlog n))的,时间复杂度是(O(nlog^2 n))的
代码
#include<bits/stdc++.h>
#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<int> 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<d[x].size();++i) {
if(x==d[x][i]) continue;
int t=explore(x,d[x][i]);
d[t].push_back(d[x][i]);
if(rt[0]==t||rt[1]==t) continue;
if(!rt[0]) rt[0]=t;
else if(!rt[1]) rt[1]=t;
}
if(rt[0]) divide(rt[0]);
if(rt[1]) divide(rt[1]);
}
const double alpha=0.75;
struct E{int v,nxt;}e[maxn<<1];
int head[maxn],Mnow,sum[maxn],vis[maxn],nrt,S,rt,mx[maxn],fa[maxn],num,tim,del[maxn];
inline void add(int x,int y) {
e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
void getrt(int x,int Fa) {
sum[x]=1;mx[x]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]==tim||e[i].v==Fa)continue;
getrt(e[i].v,x);sum[x]+=sum[e[i].v];
mx[x]=max(sum[e[i].v],mx[x]);
}
mx[x]=max(mx[x],S-sum[x]);
if(mx[x]<Mnow) Mnow=mx[x],nrt=x;
}
void clr(int x,int Fa) {
del[x]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(e[i].v==Fa||vis[e[i].v]==tim) continue;
clr(e[i].v,x);
}
}
void Dfs(int x) {
vis[x]=tim;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]==tim) continue;
Mnow=maxn,S=sum[e[i].v];getrt(e[i].v,0);
fa[nrt]=x;sum[nrt]=sum[e[i].v];Dfs(nrt);
}
}
inline void rebuild(int x) {
++tim;for(re int i=fa[x];i;i=fa[i]) vis[i]=tim;
clr(x,0);Mnow=maxn,S=sum[x],getrt(x,0);
if(rt==x) rt=nrt;
fa[nrt]=fa[x];sum[nrt]=sum[x];Dfs(nrt);
}
inline void pushup(int x) {
if(!fa[x]) {
if(del[x]) rebuild(x);
return;
}
++sum[fa[x]];if(sum[fa[x]]*alpha<sum[x]) del[fa[x]]=1;
pushup(fa[x]);if(del[x]) rebuild(x);
}
inline void ins(int x) {
int u=rt;
while(!c[x]) {
int v=explore(u,x);
if(c[v]) {
while(fa[v]!=u) v=fa[v];
u=v;continue;
}
add(u,v),add(v,u);fa[v]=u;
sum[v]=1;pushup(v);
u=v;c[v]=1;
}
}
void play(int n, int T, int dataType) {
if(n<=100&&dataType==1) {
dfs(1,0,n);return;
}
if(dataType==3) {
for(re int i=1;i<n;++i)p[i]=i+1;
srand(time(0));
std::random_shuffle(p+1,p+n);
int rt[2];rt[0]=1,rt[1]=1;
int t=p[2],u;
while(rt[1]!=t) {
u=explore(rt[1],t);
c[u]=1;rt[1]=u;
}
for(re int i=3;i<n;i++) {
int x=p[i];if(c[x]) continue;
u=explore(rt[0],x);
if(c[u]) std::swap(rt[0],rt[1]),u=explore(rt[0],x);
c[u]=1,rt[0]=u;
while(rt[0]!=x) {
u=explore(rt[0],x);
c[u]=1,rt[0]=u;
}
}
}
if(dataType==2) {
for(re int i=2;i<=n;i++) d[1].push_back(i);
divide(1);
return;
}
rt=1;for(re int i=1;i<n;i++)p[i]=i+1;
srand(time(0));std::random_shuffle(p+1,p+n);
for(re int i=1;i<n;i++) if(!c[p[i]]) ins(p[i]);
}