题目链接:优秀的树
- 时间限制:C/C++ 2000MS,其他语言 4000MS
- 内存限制:C/C++ 256MB,其他语言 512MB
给定一棵树,其所有边权重均为 1,定义 f ( u ) = ∑ v d i s ( u , v ) f(u)=\sum_{v} dis(u,v) f(u)=∑vdis(u,v), v v v 表示树上的所有结点, d i s ( u , v ) dis(u,v) dis(u,v) 表示结点 u u u 和 v v v 的简单路径的长度。
一棵树被称为“优秀”,当且仅当存在两个结点 u u u 和 v v v 满足 f ( u ) − f ( v ) = x f(u)-f(v)=x f(u)−f(v)=x。
给定 x x x,求满足 “存在两个结点 u u u 和 v v v 满足 f ( u ) − f ( v ) = x f(u)-f(v)=x f(u)−f(v)=x” 成立的树最少有多少个结点。
输入描述
输入有多组测试用例,第一行包含一个整数 t ( 1 ≤ t ≤ 1 0 5 ) t(1≤t≤10^5) t(1≤t≤105),表示接下来有 t t t 组测试用例。
每一个测试用例包含一个整数 x ( 1 ≤ x ≤ 1 0 18 ) x(1≤x≤10^{18}) x(1≤x≤1018)。
输出描述
对每一个测试用例,输出一个整数,表示能满足条件被称为 “优秀” 的树结点最少为多少。
可以证明答案总是存在的。
示例
提示
- 1 ≤ t ≤ 1 0 5 1≤t≤10^5 1≤t≤105
- 1 ≤ x ≤ 1 0 18 1≤x≤10^{18} 1≤x≤1018
理论背景
-
树的定义:
- 在树结构中,任意两个节点之间的路径是唯一的,且边的权重为1。
-
函数 f(u):
f(u)
表示从节点u
到树中所有其他节点的距离之和,即: f ( u ) = ∑ v ∈ tree dis ( u , v ) f(u) = \sum_{v \in \text{tree}} \text{dis}(u, v) f(u)=∑v∈treedis(u,v)- 这里的
dis(u, v)
是节点u
和节点v
之间的简单路径长度。
-
差值 f(u) - f(v):
- 我们关注的是
f(u) - f(v)
的值,这个值的计算依赖于u
和v
之间的关系。 - 通过选择不同的节点
u
和v
,我们可以得到不同的f(u) - f(v)
的值。
- 我们关注的是
公式推导
-
完全平方数的情况:
- 若
x
是完全平方数,即k * k = x
,那么f(u) - f(v)
的差值可以通过节点的深度和数量的关系来推导。 - 在这种情况下,输出
k / 2 + 1
是因为我们可以选择一棵特定结构的树(如完全二叉树)来满足条件。
- 若
-
偶数与范围条件:
- 当
x
在k * (k + 1)
范围内且x
为偶数时,我们可以构造一棵树,使得f(u) - f(v)
的值能够精确到这个范围,因此输出k / 2 + 2
。
- 当
-
其他情况:
- 对于其他情况,输出
k / 2 + 3
是为了确保无论x
的值如何变化,我们总能找到一棵树使得f(u) - f(v) = x
成立。
- 对于其他情况,输出
总结
这些公式的选择是基于树的结构性质、节点之间的关系以及如何通过不同的树形结构来满足 f(u) - f(v) = x
的条件。通过数学推导和对树的性质的理解,我们得出了这些公式。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while(t--)
{
long long x;
cin >> x;
long long k = sqrtl(x); // 计算x的平方根k
if(k * k == x)
cout << k << 1 + 1 << endl;
else
if(x <= k * (k + 1) && !(x & 1)) // 判断x是否在k * (k + 1)范围内且为偶数
cout << k << 1 + 2 << endl;
else
cout << k << 1 + 3 << endl;
}
return 0;
}