CHEWBACCA

link

题目废话挺多的,简单来说就是要求构造一棵完全 \(K\) 叉树,按广搜顺序编号(可以感性理解为从上到下,从左到右编号)。然后多组询问,每组询问树上两个点的距离。

一道找规律题(只能这么说了)。思路是求两个点的距离要先求它们的 LCA,然后考虑三个点的深度关系就可以了。求 LCA 部分,由于树是完全二叉树,树的深度不会太大(当然 \(K=1\) 的时候除外,特判即可),于是什么倍增、离线求都不需要了,直接一步一步向上跳即可。于是问题就转化成了如何快速地求解一个点的父亲是谁。

有一个显而易见的结论就是一棵 \(K\) 叉树的第一层只有 \(1\) 个结点,第二层会有 \(K\) 个结点,第三层会有 \(K^2\) 个结点。画个图可以知道,第二层的编号从 \(2\) 开始,而第三层的编号会从 \(K+2\) 开始,也就是说第二层的第一个节点(也就是编号 \(2\) 的结点)的 \(K\) 个儿子的编号范围是 \([K+2,K+2+(K-1)]\) 即是 \([K+2,2K+1]\),发现就这些儿子而言,他们的父亲都是 \(\lfloor\frac{X-2}{K}\rfloor+1=2\) ,再找几组孩子发现这个规律仍然成立,于是就确定了每个点父亲与它自己的关系。然后问题就简单了,当两个点不相同时每次挑选深度大的点往上跳,同时累计答案一直到两个点重合为止就可以了。代码很好写,而且似乎并没有卡那个 \(K=1\) 的情况。

#include<bits/stdc++.h>
//#define feyn
#define int long long
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline void swap(int &s1,int &s2){
	int s3=s1;s1=s2;s2=s3;return;
}

int m,n;

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(m);read(n);
	int a,b,ans;
	while(n--){
		ans=0;read(a);read(b);
		while(a^b){
			if(a<b)swap(a,b);
			a=(a-2)/m+1;ans++;
		}
		printf("%lld\n",ans);
	}
	
	return 0;
}
posted @ 2022-07-21 10:57  Feyn618  阅读(29)  评论(0编辑  收藏  举报