LOJ2512「BJOI2018」链上二次求和
有一条长度为 \(n\) 的链( \(\forall 1 \leq i < n\) ,点 \(i\) 与点 \(i+1\) 之间有一条边的无向图), 每个点有一个整数权值,第 \(i\) 个点的权值是 \(a_i\) 。现在有 \(m\) 个操作,每个操作如下:
- 操作 1(修改):给定链上两个节点 \(u\)、\(v\) 和一个整数 \(d\),表示将链上 \(u\) 到 \(v\) 唯一的简单路径上每个点权值都加上 \(d\)。
- 操作 2(询问):给定两个正整数 \(l\)、\(r\),表示求链上所有节点个数大于等于 \(l\) 且小于等于 \(r\) 的简单路径节点权值和之和。由于答案很大,只用输出对质数 \(1000000007\) 取模的结果即可。
一条节点个数为 \(k\) 的简单路径节点权值和为这条上所有 \(k\) 个节点(包括端点)的权值之和,而本题中要求是对所有满足要求的简单路径,求这一权值和的和。
由于是无向图,路径也是无向的,即点 \(1\) 到点 \(2\) 的路径与点 \(2\) 到点 \(1\) 的路径是同一条,不要重复计算。
\(n \leq 200000, m \leq 500000, m^\prime \leq 100000, 0 \leq a_i < 1000000007\)。
线段树
数据结构
前几天考过一个简单一点的,给出的是一颗树,然后每次的 \(L, R\) 是给定的。
然后可以直接点分治计算每个点的贡献,然后每次就前缀和计算即可。
对于这个题,我们可以记 \(s_i = \sum_{j = 1}^i a_j\),然后每次询问的答案就是:
然后记 \(S_i = \sum_{j = 1}^i s_j\),可以进一步化简柿子:
也就是分开考虑左端点和右端点的贡献。
刚开始我还想着直接维护 \(ans\) 的前缀和,这样的话还要对于 \(S_i\) 进行若干求和,就会比较复杂,然后我们可以注意到,只要维护了 \(S_i\) 就可以求得 \(ans\) 了,于是可以直接考虑维护 \(S_i\) 了。
考虑对于 \([l, r]\) 加上了 \(d\),那么(手动算一下系数就出来了):
然后我们可以暴力拆开式子,就会发现每次加法的贡献都是一个关于下标 \(i\) 的二次函数,那么可以用线段树维护这个二次函数即可,总体没什么细节,具体式子可以看代码。