题意
给出长度为1e5的数组和1e5次操作,每次操作可能为单点修改,也可能为区间查询
思路
数据范围是1e5,考虑用数据结构维护,树状数组或线段树都可以
树状数组是一种支持单点修改和区间查询的代码量小的数据结构,维护的信息和运算必须要满足结合律而且可差分,比如加法、乘法、异或等。
- 结合律:(x # y )# z = x # (y # z),其中#为二元运算符,比如+ * ^
- 可差分:具有逆运算的运算,即已知 x # y 和 x 可以求出y
需要注意的是:
- mod 意义下的乘法如果要差分,需要保证每个数都存在逆元(模数为质数时一定存在逆元)
- gcd、max这些信息不可差分
树状数组解决的是线段树解决的问题的子集,但是树状数组代码量少,常数小。
基本原理就是把前缀[1,n]拆成不多于logn段区间,使得这logn段区间的信息是已知的,那么合并的时候只需要合并logn段区间的信息就可以得到答案,以前需要合并n个信息
具体可以看 oiwiki
Go代码
package main import ( "fmt" ) const maxn = 1e5 + 7 var tree = make([]int,maxn) var n int func lowbit(x int) int { return x & -x } func add(idx,x int) { for idx <= n { tree[idx] += x idx += lowbit(idx) } } func query(idx int) int { ans := 0 for idx > 0 { ans += tree[idx] idx -= lowbit(idx) } return ans } func main() { var q,op,l,r int fmt.Scan(&n,&q) a := make([]int,n+1) for i := 1; i <= n; i ++ { fmt.Scan(&a[i]) add(i,a[i]) //记得要建树 } for ; q > 0; q -- { fmt.Scan(&op,&l,&r) if op == 1 { add(l,r) }else{ fmt.Println(query(r) - query(l-1)) } } }