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\),然后每次询问的答案就是:

\[ans(l, r) = \sum_{i = l}^r\sum_{j = i}^n s_j - s_{j - i} \]

  然后记 \(S_i = \sum_{j = 1}^i s_j\),可以进一步化简柿子:

\[ans(l, r) = \sum_{i = l}^r S_n - S_{i - 1} - S_{n - i} \]

  也就是分开考虑左端点和右端点的贡献。

  刚开始我还想着直接维护 \(ans\) 的前缀和,这样的话还要对于 \(S_i\) 进行若干求和,就会比较复杂,然后我们可以注意到,只要维护了 \(S_i\) 就可以求得 \(ans\) 了,于是可以直接考虑维护 \(S_i\) 了。

  考虑对于 \([l, r]\) 加上了 \(d\),那么(手动算一下系数就出来了):

\[\left\{ \begin{aligned} &S_i \gets S_i + \frac{(i - l + 1)(i - l + 2)}{2}d&& i \in [l, r]\\ &S_i \gets S_i + \frac{(r - l + 1)(r - l + 2)}{2} d + (i - r)(r - l + 1)d&& i > r \end{aligned} \right. \]

  然后我们可以暴力拆开式子,就会发现每次加法的贡献都是一个关于下标 \(i\) 的二次函数,那么可以用线段树维护这个二次函数即可,总体没什么细节,具体式子可以看代码

posted @ 2022-02-22 21:55  Werner_Yin  阅读(56)  评论(0编辑  收藏  举报