作者:G版车臣 | 来源:互联网 | 2024-12-22 14:36
本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。
### 问题背景
强强和萌萌是一对好朋友。某天他们在散步时遇到了一棵正在开花的紫荆树。这棵树不仅美丽,而且每个时刻都会新长出一个叶子节点。每个节点上有一个可爱但脆弱的小精灵,每个小精灵都有一个感受能力值Ri。两个小精灵i和j成为朋友当且仅当它们在树上的距离dist(i, j) ≤ Ri + Rj,其中dist(i, j)表示从节点i到节点j路径上所有边的边权和。
### 任务描述
给定一个初始为空的树,节点按加入顺序从1开始编号。每当一个新的叶子节点出现时,你需要立即计算并输出当前树上总共有多少对朋友。
### 解决方案概述
对于静态树,可以使用点分治算法来解决这个问题。通过将条件拆解,利用平衡树维护即可实现较为基础的点分治方法。然而,当树是动态变化的时,直接应用点分治并非最优选择。此时可以借鉴替罪羊树的思想:暴力维护树结构,并在失衡时进行重建。这样可以确保树的效率不会大幅下降。
### 具体实现
我们首先构建一个简单的点分树结构,然后在树失衡时进行静态维护。代码中使用了随机化技术(如替罪羊树)来保证数据结构的高效性。以下是简化后的代码片段:
```cpp
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef double dl;
const int N = 1e5 + 5;
const int mod = 1e9;
const dl alpha = 0.812345;
inline int read() {
// 省略读入部分
}
struct node {
int to, nxt, w;
};
// 省略其他定义及函数
int main() {
n = read();
for (int i = 1; i <= n; ++i) {
int u = read() ^ (ans % mod), w = read();
r[i] = read();
if (i == 1) {
// 初始化第一个节点
} else {
add(u, i, w);
add(i, u, w);
ans += solve(i, u, w);
check(i);
printf("%lld\n", ans);
}
}
return 0;
}
```
以上代码实现了动态树的构造与维护,确保每次新增节点后能够快速准确地计算出当前树上的朋友对数。