### **问题场景**
想象你有一棵家族树,根节点是爷爷,每个节点代表一个家庭成员,他们各自有一个钱包金额。现在需要支持两种操作:
1. **给某个家庭成员及其所有晚辈发红包**(整个子树的钱包增加)。
2. **查询某个家庭成员及其所有晚辈的钱包金额的平方和**(例如计算家族财富分布)。
我们需要高效处理这两种操作,即使家族成员数量庞大。
---
### **核心思路**
#### **1. 将树“拍扁”成数组(DFS序)**
- **问题**:树的结构复杂,直接操作子树困难。
- **解决**:通过**DFS遍历**记录每个节点的“进入时间”和“离开时间”,将子树转化为连续区间。
- **进入时间**:第一次访问节点的时间戳(类似上班打卡)。
- **离开时间**:完成该节点所有子节点访问的时间戳(类似下班打卡)。
**示例**:
```
树结构:
1
/ \
2 3
/ \
4 5
DFS遍历顺序:1 -> 2 -> 4 -> 5 -> 3
进入时间:in[1]=1, in[2]=2, in[4]=3, in[5]=4, in[3]=5
离开时间:out[1]=5, out[2]=4, out[4]=3, out[5]=4, out[3]=5
```
- 节点2的子树对应区间 `[in[2], out[2]] = [2,4]`,包含节点2、4、5。
---
#### **2. 线段树:高效管理区间**
- **线段树**是一种数据结构,可以快速处理**区间查询**和**区间更新**。
- **结构**:将数组划分成多个区间,每个树节点存储一个区间的统计值(如和、平方和)。
- **示例**:
- 数组 `[A, B, C, D]` 的线段树:
```
[A-D](总和)
/ \
[A-B] [C-D]
/ \ / \
[A] [B] [C] [D]
```
---
#### **3. 懒标记(Lazy Propagation)**
- **问题**:频繁更新整个区间效率低(如给1万人发红包,逐个更新太慢)。
- **解决**:延迟更新,先记录“欠账”,需要时再实际更新。
- **懒标记**:记录某个区间需要增加的值,暂时不传递到子节点。
- **触发时机**:当需要查询或更新子区间时,才将懒标记下推。
**示例**:
- 给区间`[1-4]`发红包+10,先标记该区间懒标记为10,不更新子节点。
- 当查询子区间`[1-2]`时,才将懒标记下推,并更新实际值。
---### **代码逐行解析**
#### **1. 输入与初始化**
```java
// 读取输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken()); // 节点数
Q = Integer.parseInt(st.nextToken()); // 操作数
// 读取每个节点的初始金额
weight = new int[N + 1];
st = new StringTokenizer(br.readLine());
for (int i = 1; i <= N; i++) {
weight[i] = Integer.parseInt(st.nextToken());
}
// 构建树的邻接表
tree = new ArrayList[N + 1];
for (int i = 1; i <= N; i++) {
tree[i] = new ArrayList<>();
}
for (int i = 1; i < N; i++) {
st = new StringTokenizer(br.readLine());
&n