📅  最后修改于: 2023-12-03 15:42:16.548000             🧑  作者: Mango
给定一个由$n$个元素组成的数组$A$,处理以下两个操作:
使用分块算法实现该数据结构。
第一行包含两个整数$n$和$m$,表示数组$A$的大小和操作次数。
第二行包含$n$个整数,表示数组$A$的初始值。
接下来$m$行,每行描述一个操作,格式为以下两种之一:
1 l r
- 表示查询区间$[l, r]$中所有元素的和。2 x v
- 表示将$A_x$的值修改为$v$。对于每个查询操作输出查询结果。
6 7
1 2 3 4 5 6
1 2 5
2 3 6
1 1 6
2 3 8
1 1 6
1 3 5
1 2 4
14
20
15
9
使用分块算法解决该问题,将数组分成$\sqrt{n}$份。
对于查询操作,由于数组中某些元素已经被修改过了,所以要在查询前进行所有修改操作。
然后对于查询的区间$[L, R]$,先查看L和R所在块是否相同,如果相同,则在该块中暴力求解。如果不同,则先在起始块中从L开始暴力求出L所在块到末尾的所有元素的和,再在结束块中从开头到R位置的元素进行暴力求解,最后在中间的若干块中求出所有元素的和。
对于修改操作,只需要修改对应位置的元素值即可。
from math import sqrt, ceil
class Block:
def __init__(self, data, size):
self.data = data # 块中的元素
self.size = size # 块的大小
self.sums = [0] * self.size # 前缀和数组
# 初始化块的前缀和数组
for i in range(size):
self.sums[i] = self.data[i] + (self.sums[i-1] if i-1>=0 else 0)
def update(self, index, value):
# 修改块中某个元素值后,同步更新前缀和数组
self.sums[index % self.size] += value - self.data[index % self.size]
self.data[index % self.size] = value
def query(self, left, right):
# 查询块中两个位置之间的所有元素的和
left_index, right_index = left % self.size, right % self.size
if left_index <= right_index:
return self.sums[right_index] - (self.sums[left_index - 1] if left_index>0 else 0)
else:
return self.sums[-1] - (self.sums[left_index - 1] if left_index>0 else 0) + self.sums[right_index]
class BlockArray:
def __init__(self, data):
self.data = data
self.block_size = ceil(sqrt(len(data)))
self.blocks = [None] * self.block_size
# 初始化每个块
for i in range(self.block_size):
left = self.block_size * i
right = left + self.block_size - 1
right = min(right, len(data)-1)
self.blocks[i] = Block(data[left:right+1], right-left+1)
def update(self, index, value):
# 修改某个元素值
self.data[index] = value
self.blocks[index//self.block_size].update(index, value)
def query(self, left, right):
# 查询区间[left, right]的所有元素的和
res = 0
left_block, left_index = left // self.block_size, left % self.block_size
right_block, right_index = right // self.block_size, right % self.block_size
# 如果查询区间在同一个块中,则暴力查询即可
if left_block == right_block:
res = self.blocks[left_block].query(left_index, right_index)
else:
res += self.blocks[left_block].query(left_index, -1)
res += self.blocks[right_block].query(0, right_index)
for i in range(left_block+1, right_block):
res += self.blocks[i].sums[-1]
res += self.data[left_block*self.block_size-1] if left_index==0 and left_block>0 else 0
res += self.data[right_block*self.block_size] if right_index==self.block_size-1 and right_block<len(self.blocks)-1 else 0
return res
if __name__ == '__main__':
n, m = map(int, input().split())
data = list(map(int, input().split()))
block_array = BlockArray(data)
for _ in range(m):
op = list(map(int, input().split()))
if op[0] == 1:
print(block_array.query(op[1]-1, op[2]-1))
elif op[0] == 2:
block_array.update(op[1]-1, op[2])