用两个 Fenwick 树维护等差数列区间加,并在单点查询时恢复当前值。
OJ: luogu
题目 ID: P1438
难度:普及+/提高
标签:树状数组差分等差数列python
日期: 2026-07-16 23:59
题意
给 [l,r] 加上首项为 K、公差为 D 的等差数列,并查询某个位置的值。
思路
第 i 项增加 K + (i-l)D = (K-lD) + iD。因此只要分别维护“常数项系数”和“位置系数”的差分数组即可:在 [l,r] 的差分端点加上这两个系数,单点查询时取两个 Fenwick 前缀和。
Python 知识
array("q")保存整数差分,避免 Python 对象列表的额外空间。iter(map(int, read().split()))让所有整数共享一次解析流程。- 生成器表达式
(next(data) for _ in range(4))适合读取变长操作。
代码
python
import sys
from array import array
data = iter(map(int, sys.stdin.buffer.read().split()))
n, operations = next(data), next(data)
values = [next(data) for _ in range(n)]
constant = array("q", [0]) * (n + 2)
linear = array("q", [0]) * (n + 2)
def add(tree, index, value):
while index <= n:
tree[index] += value
index += index & -index
def prefix(tree, index):
result = 0
while index:
result += tree[index]
index -= index & -index
return result
def range_add(tree, left, right, value):
add(tree, left, value)
if right < n:
add(tree, right + 1, -value)
answers = []
for _ in range(operations):
operation = next(data)
if operation == 1:
left, right, first, difference = (next(data) for _ in range(4))
range_add(constant, left, right, first - left * difference)
range_add(linear, left, right, difference)
else:
position = next(data)
answers.append(str(values[position - 1] + prefix(constant, position)
+ position * prefix(linear, position)))
print("\n".join(answers))原有 C++ 版本仍保留:
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-16 23:46
* update_at: 2026-07-16 23:46
*/
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}复杂度
每次修改和查询均为 O(log n),空间 O(n)。
总结
等差数列看似需要修改很多位置,拆成“常数项 + 下标系数”后仍然只是两个差分端点。