题解 CF1761G 【Centroid Guess】
这里是官方题解,CF 官方英文题解由此题解翻译得到。
假设我们现在确定了树的重心在
设
设集合
接下来考虑通过
现在问题是找到点对
我们取一个常数
设这
此时我们求出了不包含 LCA 的以
我们从
仅仅对于原始随机到的
正确性证明:
若原树的重心不在
fun fact:
-
这个题本来有 Easy 版本,但是赛前一个星期发现 Easy 版本可以用一个集训队互测题的做法解决,于是就删掉了。
-
这个题在验题的时候被 Um_nik 用错误率约为
0.85\% 的做法过了,于是造了500 组数据,此外还有不止一个错误率极低的做法。
以下是 std(Main Correct Solution):
#include<bits/stdc++.h>
using namespace std;
#define N 75005
#define S 316
#define M 640
int read(){
int w=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')w=w*10+c-48,c=getchar();
return w;
}
void report(int x){
printf("! %d\n",x);
exit(0);
}
const int lim=2e5;
int n,m,p[N],dis[M][M],fa[M],dep[M],d1[N],d2[N],siz[M],maxsiz[M],r[N],w[N],du,dv,idx;
bool vis[M];
vector<int>e[M],g[M];
mt19937 rnd(time(NULL)^(unsigned long long)(new char));
int rad(int x,int y){
return rnd()%(y-x+1)+x;
}
bool in(int x,int y,int z){
return dis[x][y]+dis[y][z]==dis[x][z];
}
void get(int u){
vis[u]=1;
for(auto v:e[u])
get(v);
}
bool work(int u){
for(auto v1:e[u]){
int l=0;
for(auto v2:e[u])
if(!in(v1,u,v2))l=max(l,(dis[v1][u]+dis[v1][v2]-dis[u][v2])/2);
if(!l)continue;
l=dis[u][v1]-l;
for(auto v2:e[u])
if(!in(v1,u,v2))get(v2);
idx++;
for(int i=1;i<idx;i++)
dis[i][idx]=dis[idx][i]=dis[u][i]+(vis[i]?-l:l);
memset(vis+1,0,sizeof(bool)*idx);
vector<int>x;
for(auto v2:e[u])
if(!in(v1,u,v2))e[idx].push_back(v2);
else x.push_back(v2);
return e[u]=x,e[u].push_back(idx),1;
}
return 0;
}
void dfs1(int u){
while(work(u));
for(auto v:e[u])
dfs1(v),g[v].push_back(u);
}
void dfs2(int u,int ft){
siz[u]=u<=m?1:0;
for(auto v:e[u])
if(v!=ft)dfs2(v,u),siz[u]+=siz[v],maxsiz[u]=max(maxsiz[u],siz[v]);
maxsiz[u]=max(maxsiz[u],m-siz[u]);
}
void dfs3(int u,int ft){
int sn=0;
for(auto v:e[u])
if(v!=ft&&siz[v]>siz[sn])sn=v;
if(sn)dfs3(sn,u);
else dv=du?p[u]:0,du=du?du:p[u];
}
signed main(){
n=read(),m=min(n,S),idx=m;
for(int i=1;i<=n;i++)
p[i]=i,swap(p[i],p[rad(1,i)]);
for(int i=1;i<=m;i++)
for(int j=i+1;j<=m;j++)
printf("? %d %d\n",p[i],p[j]);
fflush(stdout);
for(int i=1;i<=m;i++)
for(int j=i+1;j<=m;j++)
dis[i][j]=dis[j][i]=read();
for(int i=2;i<=m;i++){
int maxn=0,maxid=1;
for(int j=2;j<=m;j++)
if(i!=j&&in(1,j,i)&&dis[1][j]>maxn)maxn=dis[1][j],maxid=j;
e[maxid].push_back(i);
}
dfs1(1);
for(int i=1;i<=idx;i++)
for(auto j:g[i])
e[i].push_back(j);
dfs2(1,0);
int minn=m+1,minid=0;
for(int i=1;i<=idx;i++)
if(maxsiz[i]<minn)minn=maxsiz[i],minid=i;
dfs2(minid,0);
sort(e[minid].begin(),e[minid].end(),[&](int x,int y){return siz[x]>siz[y];});
dfs3(e[minid][0],minid),dfs3(e[minid][1],minid);
for(int i=1;i<=n;i++){
if(du!=i)printf("? %d %d\n",du,i);
if(dv!=i)printf("? %d %d\n",dv,i);
}
fflush(stdout);
for(int i=1;i<=n;i++)
d1[i]=du==i?0:read(),d2[i]=dv==i?0:read();
int len=d1[dv];
for(int i=1;i<=n;i++)
if(d1[i]+d2[i]==len)r[d1[i]]=i;
for(int i=1;i<=n;i++)
w[(d1[i]-d2[i]+len)>>1]++;
for(int i=0,now=0;;i++)
now+=w[i],now*2>n?report(r[i]):void();
return 0;
}