ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Dist

2022-04-29 22:03:22  阅读:217  来源: 互联网

标签:10 一个点 个点 md long ax Dist


有一棵 n 个点的 k 叉树,点的编号为 \(1…n\),它的结构描述如下:

1 号点为根节点,如果一个点到 1 号点经过的最少边数为 i 则称它在第 i 层里。
第 i 层的第 j 个点的父亲是 第 i−1 层的第$ ⌊(j−1)/k⌋+1$ 个点。
第 i 层的第 j 个点的编号为 \(∑^{i−1}_{p=0}k^p+j\) 。
从 3 可以看出,除了最深的一层,其余层的点数都是满的(即第 \(i\) 层有 \(k^i\) 个点)
图中画了一个 k=3 的情形:

image

q 次询问每次询问树上点 x 到点 y 的距离(经过的最少边数)。

输入格式
第一行三个整数 \(n,k,q\) 。

接下来的$ q$ 行每行两个整数$ x,y $。

输出格式
对于每组询问,输出$ x,y$ 之间的距离。

样例
input

9 3 3
8 9
5 7
8 4

output

2
2
3

数据范围
时间限制: 2s
空间限制: 256MB
对于 20% 的数据,$ n,q≤10^3$ 。

对于 50% 的数据, \(n,q≤10^5\) 。

对于 100% 的数据, \(n≤10^{15},2≤k≤10^3,q≤10^5\) 。

发现这棵树的层数应该只有\(log n\)层。所以考虑直接暴力,就是先把两个点跳到同一层,然后再一起往上跳。

我们先研究一下一个点\(x\)的父亲是谁,很明显,\(x\)的父亲是\(⌊(x-2)/k⌋+1\).然后我们还要求出一个点的层数,可以暴力求,但我这里用了二分。然后往上跳就可以了。

#include<cstdio>
using namespace std;
long long n,x,y,pw[60];
int k,q,m,ax,ay,l,r,ans,md;
int askdep(long long x)
{
	l=0,r=m;
	while(l<=r)
	{
		md=l+r>>1;
		if(pw[md]<x)
			l=md+1;
		else
			r=md-1; 
	}
	return l;
}
int main()
{
	scanf("%lld%d%d",&n,&k,&q);
	pw[0]=1;
	for(m=1;pw[m-1]*k<=n;m++)
		pw[m]=pw[m-1]*k;
	--m;
	for(int i=1;i<=m;i++)
		pw[i]+=pw[i-1];
	while(q--)
	{
		scanf("%lld%lld",&x,&y);
		ax=askdep(x),ay=askdep(y),ans=0;
		while(ax>ay)
			ans++,x=(x-2)/k+1,--ax;
		while(ax<ay)
			ans++,y=(y-2)/k+1,--ay;
		while(x!=y)
			ans+=2,x=(x-2)/k+1,y=(y-2)/k+1;
		printf("%d\n",ans);
	}
} 

标签:10,一个点,个点,md,long,ax,Dist
来源: https://www.cnblogs.com/mekoszc/p/16208438.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有