题意
给出长度为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))
}
}
}

京公网安备 11010502036488号