题目
Description
给定一棵树,设计数据结构支持以下操作
1 u v d 1 \;u\;v\;d 1uvd 表示将路径 ( u , v ) (u,v) (u,v) 加 d d d
2 u v 2\;u\;v 2uv 表示询问路径 ( u , v ) (u,v) (u,v) 上点权绝对值的和
Input
第一行两个整数 n n n 和 m m m,表示结点个数和操作数
接下来一行 n n n 个整数 a i a_i ai,表示点 i i i 的权值
接下来 n − 1 n-1 n−1 行,每行两个整数 u , v u,v u,v 表示存在一条 ( u , v ) (u,v) (u,v) 的边
接下来 m m m 行,每行一个操作,输入格式见题目描述
Output
对于每个询问输出答案
Sample Input
4 4
-4 1 5 -2
1 2
2 3
3 4
2 1 3
1 1 4 3
2 1 3
2 3 4
Sample Output
10
13
9
Hint
对于 100 % 100\% 100% 的数据, n , m < = 1 0 5 n,m <= 10^5 n,m<=105 且 0 < = d , ∣ a i ∣ < = 1 0 8 0<= d,|a_i|<= 10^8 0<=d,∣ai∣<=108
思路
树链剖分+线段树,考虑如何维护这棵线段树。
由于这题是绝对值和,维护 lazytag 时,正负性不容易处理,考虑往区间和上靠。
注意到:区间绝对值之和 = = = 2 × 2 \times 2×区间正数和 − - − 区间和,所以本题转化成了维护区间正数和。
在线段树中,需要再维护几个东西:
- maxf:区间最大的负数
- sum:区间正数和
- num:区间正数的个数
- tag:sum 的懒标记
- tagg:maxf 的懒标记(一开始大e了,没有闪,忘了 maxf 也是要下传懒标记的了)
修改时,注意到每一次增加的量 d ≥ 0 d \geq 0 d≥0,所以每一个数只会被从负数变成正数一次,那么这样的操作最多总共只会出现 n n n 次,对于这些操作,我们就将线段树递归到底,暴力修改。
而对于其余的操作,我们只需正常的区间修改即可。
如何判断一次操作后,区间内有负数变成正数呢?这就用到了 maxf,如果 m a x f + d > 0 maxf