题目背景
对应的选择、判断题:试题 - GESP 202506 C++ 六级 - 洛谷有题
题目描述
给定一棵有 109 个结点的有根树,这些结点依次以 1,2,...,109 编号,根结点的编号为 1。对于编号为 k(2≤k≤109)的结点,其父结点的编号为 k 的因数中除 k 以外最大的因数。
现在有 q 组询问,第 i(1≤i≤q)组询问给定 xi,yi,请你求出编号分别为 xi,yi 的两个结点在这棵树上的距离。两个结点之间的距离是连接这两个结点的简单路径所包含的边数。
输入格式
第一行,一个正整数 q,表示询问组数。
接下来 q 行,每行两个正整数 xi,yi,表示询问结点的编号。
输出格式
输出共 q 行,每行一个整数,表示结点 xi,yi 之间的距离。
输入输出样例
输入 #1复制
3
1 3
2 5
4 8
输出 #1复制
1
2
1
输入 #2复制
1
120 650
输出 #2复制
9
说明/提示
对于 60% 的测试点,保证 1≤xi,yi≤1000。
对于所有测试点,保证 1≤q≤1000,1≤xi,yi≤109。
代码实现:
cpp
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
ll min_factor(ll n)
{
if(n%2 ==0) return 2;
for(ll i=3;i*i<=n;i+=2)
{
if(n%i == 0) return i;
}
return n;
}
ll get_fa(ll x)
{
ll p = min_factor(x);
return x / p;
}
int get_depth(ll x)
{
int d = 0;
while(x != 1)
{
x = get_fa(x);
d++;
}
return d;
}
ll jump(ll a, int k)
{
while(k--)
{
a = get_fa(a);
}
return a;
}
ll lca(ll x, ll y)
{
int dx = get_depth(x);
int dy = get_depth(y);
if(dx > dy)
{
x = jump(x, dx - dy);
}
else
{
y = jump(y, dy - dx);
}
if(x == y) return x;
while(true)
{
x = get_fa(x);
y = get_fa(y);
if(x == y) return x;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int q;
cin >> q;
while(q--)
{
ll x,y;
cin >> x >> y;
int dx = get_depth(x);
int dy = get_depth(y);
ll ancestor = lca(x,y);
int dlca = get_depth(ancestor);
int ans = dx + dy - 2 * dlca;
cout << ans << '\n';
}
return 0;
}