📅  最后修改于: 2023-12-03 15:41:09.962000             🧑  作者: Mango
本篇文章是针对《算法竞赛入门经典》第1.6节须藤放置的问题2进行介绍。
给定一个长度为 $n$ 的整数序列 $A$,初始时序列中所有元素均为 $0$。现在有 $m$ 次操作,每次操作给出两个整数 $l$ 和 $r$,要求将 $A$ 中下标在区间 $[l,r]$ 内的所有元素加 $1$。请你最终输出 $A$ 中每个元素的值。
我们可以使用差分数组来解决这个问题。
差分数组是原数组的相邻元素之差所组成的数组。具体地,设原数组为 $A$,则差分数组 $B$ 的定义为:
$$B_i=A_i-A_{i-1} \quad (2\leq i\leq n)$$
原数组的前缀和 $P$ 满足:
$$P_i = \sum_{j=1}^i A_j \quad (1\leq i\leq n)$$
而差分数组的前缀和 $Q$ 满足:
$$Q_i=\sum_{j=1}^i B_i = A_i-A_1 \quad (2\leq i\leq n)$$
在进行区间加时,我们只需将差分数组 $B$ 中下标在区间 $[l,r]$ 内的元素 $+1$,即 $B_l \gets B_l+1$,$B_{r+1} \gets B_{r+1}-1$。
最后,我们可以根据差分数组 $B$ 的前缀和 $Q$ 得到原数组 $A$:
$$\begin{aligned}A_1 &= Q_1 \ A_i &= Q_i-Q_{i-1} \quad (2\leq i\leq n)\end{aligned}$$
下面是一个 Python 实现例子:
n, m = map(int, input().split())
B = [0] * (n + 1)
for i in range(m):
l, r = map(int, input().split())
B[l] += 1
if r + 1 <= n:
B[r + 1] -= 1
A = [0] * (n + 1)
for i in range(2, n + 1):
B[i] += B[i - 1] # 差分数组求前缀和
for i in range(1, n + 1):
A[i] = B[i] - B[i - 1] # 根据差分数组求原数组
print(*A[1:]) # 输出结果
这是一个 $\Theta(m+n)$ 的算法,其中 $m$ 表示操作次数,$n$ 表示数组长度。