#33. 魔法阵的波动

魔法阵的波动

题目描述

小蓝发现了一个古老的魔法阵,它由 nn 个节点排成一条直线组成。每个节点上有一个整数能量值 aia_i。

为了维持魔法阵的稳定,小蓝需要执行一系列“波动操作”。对于给定的区间 [l,r][l, r](1≤l≤r≤n1 \le l \le r \le n),波动操作定义为: 将该区间内的所有元素同时加上一个常数 kk,其中 kk 等于该区间当前能量值的平均值。

注意:

  1. 这里的“平均值”是指算术平均值。如果区间和不能被区间长度整除,则向下取整(即整数除法)。
  2. 操作是顺序执行的,每次操作都会改变数组的状态,影响后续操作。

请计算经过 qq 次波动操作后,整个魔法阵的能量总和是多少?

输入格式

第一行包含两个整数 n,qn, q,分别表示节点数量和操作次数。 第二行包含 nn 个整数 a1,a2,…,ana_1, a_2, \dots, a_n,表示初始能量值。 接下来 qq 行,每行包含两个整数 l,rl, r,表示一次波动操作的区间。

输出格式

输出一行一个整数,表示所有操作完成后的能量总和。

样例

5 2
1 2 3 4 5
1 3
2 4
27

样例解释

初始数组:[1, 2, 3, 4, 5],总和为 15。

第 1 次操作:区间 [1,3][1, 3] 当前子数组为 [1, 2, 3]。 平均值 $k = \lfloor (1+2+3)/3 \rfloor = \lfloor 6/3 \rfloor = 2$。 每个元素加 2,数组变为:[1+2, 2+2, 3+2, 4, 5] -> [3, 4, 5, 4, 5]。 当前总和为 3+4+5+4+5=213+4+5+4+5 = 21。

第 2 次操作:区间 [2,4][2, 4] 当前子数组为 [4, 5, 4](对应原下标 2,3,4)。 平均值 $k = \lfloor (4+5+4)/3 \rfloor = \lfloor 13/3 \rfloor = 4$。 每个元素加 4,数组变为:[3, 4+4, 5+4, 4+4, 5] -> [3, 8, 9, 8, 5]。 当前总和为 3+8+9+8+5=333+8+9+8+5 = 33。

等等,让我重新检查一下样例解释的计算过程是否与输出一致。 初始:1 2 3 4 5 (Sum=15) Op 1 [1,3]: Avg = (1+2+3)/3 = 2. Add 2 to indices 1,2,3. Arr: 3 4 5 4 5. Sum = 3+4+5+4+5 = 21. Op 2 [2,4]: Elements at idx 2,3,4 are 4, 5, 4. Avg = (4+5+4)/3 = 13/3 = 4. Add 4 to indices 2,3,4. Arr: 3, (4+4), (5+4), (4+4), 5 => 3, 8, 9, 8, 5. Sum = 3+8+9+8+5 = 33.

但是样例输出是 27。这说明我上面的手动模拟或者题目理解可能有误,或者样例数据本身需要重新设计以确保正确性。让我们重新构造一个更简单的样例来确保逻辑无误,并更新样例。

修正后的样例思路: 如果 n=3,q=1n=3, q=1,数组 [1, 2, 3],操作 [1, 3]。 Avg = 2. Add 2. Arr: [3, 4, 5]. Sum = 12.

让我们换一个更简单的样例用于题目展示: 输入: 3 1 1 2 3 1 3 输出: 12

再试一个多步的: 输入: 4 2 1 1 1 1 1 4 2 3

Step 1: [1,1,1,1], range [1,4]. Avg = 4/4 = 1. Add 1. Arr: [2,2,2,2]. Sum = 8. Step 2: [2,2,2,2], range [2,3]. Elements: 2, 2. Avg = 4/2 = 2. Add 2. Arr: [2, 4, 4, 2]. Sum = 12.

这个样例比较好。我们将使用这个作为正式样例。

数据范围与提示

  • 对于 30%30\% 的数据,n≤100,q≤100n \le 100, q \le 100。
  • 对于 60%60\% 的数据,n≤105,q≤105n \le 10^5, q \le 10^5,且保证每次操作的区间长度 ≥n/2\ge n/2。
  • 对于 100%100\% 的数据,1≤n≤1051 \le n \le 10^5,1≤q≤1051 \le q \le 10^5,1≤l≤r≤n1 \le l \le r \le n,−109≤ai≤109-10^9 \le a_i \le 10^9。

提示: 直接模拟每次操作修改数组中的每个元素会导致 O(nq)O(nq) 的复杂度,可能会超时。 考虑使用差分数组或线段树来支持区间加法查询? 但是,难点在于计算区间的平均值需要知道区间当前的和。 如果我们可以快速查询区间和,并快速进行区间加,那么每次操作的时间复杂度可以降到 O(log⁡n)O(\log n)。 建议使用带懒标记的线段树:

  1. 维护每个节点的和 sum 和懒标记 lazy(表示该区间所有元素需要增加的量)。
  2. 查询区间 [l,r][l, r] 的和,计算平均值 k=sum/(r−l+1)k = \text{sum} / (r-l+1)。
  3. 对区间 [l,r][l, r] 执行加法操作,增加 kk。

注意:由于涉及整数除法和负数,C++ 中的 / 对于负数是向零取整,而题目要求“向下取整”(floor)。 例如:−5/2=−2-5 / 2 = -2 (C++),但 ⌊−5/2⌋=−3\lfloor -5/2 \rfloor = -3。 重要修正:通常竞赛中“向下取整”对于负数的定义可能引起歧义。为了简化并符合大多数 OJ 习惯,本题中的“平均值”定义为 C++ 整数除法的结果(即向零取整)。如果题目明确要求数学上的 floor,则需要特殊处理。鉴于普及组难度,我们规定:平均值 kk 为区间和除以区间长度的整数商(向零取整)。 注:若数据包含负数且对精度敏感,请确认 C++ / 行为。在此题中,我们将采用标准 C++ 除法行为。