Live2D

Nauuo and Binary Tree 题解

link

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;
}
posted @ 2022-10-27 22:22  Dark_Romance  阅读(43)  评论(0编辑  收藏  举报