https://www.luogu.com.cn/problem/P3374
题目描述
如题,已知一个数列,你需要进行下面两种操作:
-
将某一个数加上 xx
-
求出某区间每一个数的和
输入格式
第一行包含两个正整数 n,mn,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 mm 行每行包含 33 个整数,表示一个操作,具体如下:
-
1 x k
含义:将第 xx 个数加上 kk -
2 x y
含义:输出区间 [x,y][x,y] 内每个数的和
输出格式
输出包含若干行整数,即为所有操作 22 的结果。
输入输出样例
输入 #1复制
5 5 1 5 4 2 3 1 1 3 2 2 5 1 3 -1 1 4 2 2 1 4
输出 #1复制
14 16
说明/提示
【数据范围】
对于 30\%30% 的数据,1 \le n \le 81≤n≤8,1\le m \le 101≤m≤10;
对于 70\%70% 的数据,1\le n,m \le 10^41≤n,m≤104;
对于 100\%100% 的数据,1\le n,m \le 5\times 10^51≤n,m≤5×105。
样例说明:
故输出结果14、16
代码:
n,m=map(int,input().split())
a=[0]+list(map(int,input().split()))
tr=[0]*(n*4+1)#表示节点区间和
def lp(p): return p*2 #左节点
def rp(p): return p*2+1 #右节点
def mid(l,r): return (l+r)//2
def pushup(p): #用左右孩子来更更新当前点
tr[p]=tr[lp(p)]+tr[rp(p)]
def build(l,r,p):#建树
if l==r:#
tr[p]=a[l]
return
m=mid(l,r)
build(l,m,lp(p))
build(m+1,r,rp(p))
pushup(p)
def update(pos,v,l,r,p):#更新节点,更新叶子结点,更新父结点
if l==r:#位置,加的值,节点左右区间,节点
tr[p]=tr[p]+v
return
m=mid(l,r)
if pos<=m:
update(pos,v,l,m,lp(p))
else:
update(pos,v,m+1,r,rp(p))
pushup(p)#路径上的所有节点被更新
#回溯的到父亲结点 u的时候,此时 u在左右孩子都已经更新完毕,所以可以利用此时左右孩子的值来更新 u的值。
def query(a,b,l,r,p):
if a<=l and r<=b:
return tr[p]
m=mid(l,r)
ret=0
if a<=m: ret=ret+query(a,b,l,m,lp(p))
if b>=m+1: ret=ret+query(a,b,m+1,r,rp(p))
return ret
build(1,n,1)#建树
la=[]
for i in range(m):
x1,x2,x3=map(int,input().split())
if x1==1:
update(x2,x3,1,n,1)
else:
s=query(x2,x3,1,n,1)
la.append(s)
for j in la:
print(j)
#洛谷只能跑出七个例子,python 太慢超时