307. 区域和检索 - 数组可修改
线段数组
模板(也可根据线段树的图示思考)
class NumArray {
private:
vector<int> tree;
vector<int> hj;
int n;
public:
//树状数组基本操作 lowbit(x) 是返回 x 的最后一位1及其后面0或空组成的二进制数
// 9&-9 -> 1001&0111 -> 0001 (二进制) ->1 (十进制)
int lowbit(int i){
return i&-i;
}
void add(int idx,int v){
for(int i=idx;i<=n;i+=lowbit(i)) tree[i]+=v;
}
int query(int x){
int ans=0;
for(int i=x;i>0;i-=lowbit(i)) ans+=tree[i];
return ans;
}
NumArray(vector<int>& nums) {
hj=nums;
n=nums.size();
tree.resize(n+1);
for(int i=0;i<n;i++){
add(i+1,nums[i]);
}
}
void update(int index, int val) {
add(index+1,val-hj[index]);
hj[index]=val;
}
int sumRange(int left, int right) {
return query(right+1)-query(left);
}
};
线段树
u<<1与u<<1|1 分别为 tr[u] 的左子节点和右子节点
class Node{
public:
int l;
int r;
int v;
Node(int _l,int _r){
l=_l;
r=_r;
v=0;
}
Node(){}
};
class NumArray {
private:
vector<Node> tr;
vector<int> nums;
//创建 线段树
void build(int u,int l,int r){
tr[u]=Node(l,r);
if(l==r) return;
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
//更新 x 的值 如果要改变某个范围的值传参将x->(l,r)可以
void update_2(int u,int x,int v){
if(tr[u].r==x&&tr[u].l==x) {
tr[u].v+=v;
return;
}
int mid=(tr[u].l+tr[u].r)>>1;
if(x<=mid) update_2(u<<1,x,v);
else update_2(u<<1|1,x,v);
pubsum(u);
}
//求(l,r)范围的值
int query(int u,int l,int r){
if(l<=tr[u].l&&tr[u].r<=r) return tr[u].v;
int mid=(tr[u].l+tr[u].r)>>1;
int ans=0;
if(l<=mid) ans+=query(u<<1,l,r);
if(r>mid) ans+=query(u<<1|1,l,r);
return ans;
}
void pubsum(int u){
tr[u].v=tr[u<<1].v+tr[u<<1|1].v;
}
public:
NumArray(vector<int>& _nums){
nums=_nums;
int n=nums.size();
tr.resize(4*n);
build(1,1,n);
for(int i=0;i<n;i++) update_2(1,i+1,nums[i]);
}
void update(int index, int val) {
update_2(1,index+1,val-nums[index]);
nums[index]=val;
}
int sumRange(int left, int right) {
return query(1,left+1,right+1);
}
};