Solution
超级有意思的题目,可惜还是做不出来。/kk
我们首先看出我们可以求出每一个点的深度。然后考虑深度从小到大考虑对于每一个点找出它的父亲。
你发现如果求出两个点之间的距离就可以立马求出两个点的lca。但是如果我们从lca再到节点暴力找我们显然会询问爆炸。所以我们需要对于每一个节点用 \(\Theta(\log n)\) 查询出父亲。所以我们考虑重链剖分。如果当前节点的链尾不是查询节点的父亲,我们求出其链尾与查询节点的lca,可以发现一定会走这个lca的轻边,那么我们这样持续操作就可以了。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 3005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
vector <int> Sta[MAXN];
int n,fa[MAXN][21],son[MAXN][2],dep[MAXN],siz[MAXN],lst[MAXN];
int getit (int x,int y){
cout << "? " << x << " " << y << endl;
int t;cin >> t;return t;
}
int getclimb (int u,int s){
for (Int i = 20;~i;-- i) if (s >> i & 1) u = fa[u][i];
return u;
}
void dfs (int x){
if (!x) return ;
dfs (son[x][0]),dfs (son[x][1]),siz[x] = 1 + siz[son[x][0]] + siz[son[x][1]];
if (siz[son[x][0]] > siz[son[x][1]]) lst[x] = lst[son[x][0]];
else lst[x] = lst[son[x][1]];
if (siz[x] == 1) lst[x] = x;
}
signed main(){
read (n);int mxd = 0;
for (Int i = 2;i <= n;++ i) dep[i] = getit (1,i),chkmax (mxd,dep[i]),Sta[dep[i]].push_back (i);
for (Int d = 0;d < mxd;++ d){
dfs (1);
for (Int x : Sta[d + 1]){
int now = 1;
while (dep[now] != dep[x] - 1){
int t = lst[now],dis = (dep[x] + dep[t] - getit (x,t)) >> 1;
while (dep[t] > dis) t = fa[t][0];
if (dep[t] == dep[x] - 1){now = t;break;}
if (siz[son[t][0]] > siz[son[t][1]]) now = son[t][1];
else now = son[t][0];
}
fa[x][0] = now,son[now][!!son[now][0]] = x;
for (Int i = 1;i <= 20;++ i) fa[x][i] = fa[fa[x][i - 1]][i - 1];
}
}
cout << "!";
for (Int x = 2;x <= n;++ x) cout << " " << fa[x][0];
cout << endl;
return 0;
}
标签:int,题解,void,Tree,son,Nauuo,lst,MAXN,siz
From: https://www.cnblogs.com/Dark-Romance/p/16834248.html