树状数组学习笔记

树状数组学习笔记

友链

树状数组是一种支持很多操作,且常数很小的数据结构,ta支持区间查询,修改与单点的查询与修改。

ta的操作基于二进制,如图:
图片

数组 \(c\) 表示区间的和,每个 \(c_i\) 都有一个关辖的区间,那么问题来了,怎么判断管辖的区间呢?

这个时候 \(lowbit\) 就可以帮助我们:

int lowbit(int x){
    // x 的二进制中,最低位的 1 以及后面所有 0 组成的数。
    // lowbit(0b01011000) == 0b00001000
    //          ~~~~^~~~
    // lowbit(0b01110010) == 0b00000010
    //    
    return x&(-x);
}

lowbit 表示 最低位 1和后面所有 0 组成的数。

最普通的树状数组支持单点修改,去间查询。

code:

#include<bits/stdc++.h>

using namespace std;

const int N=1e6+10;
long long c[N],a[N],n,q;
long long lowbit(int x) {return (x&-x);}
void add(int x,int v){
	while(x<=n){
		c[x]+=v;
		x+=lowbit(x);
	}
}
long long sum(int x){
	long long ans=0;
	while(x>0){
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
signed main(){
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) add(i,a[i]);
	while(q--){
		int op;
		cin>>op;
		if(op==1){
			int x,v;
			cin>>x>>v;
			add(x,v);
		}else{
			int l,r;
			cin>>l>>r;
			cout<<sum(r)-sum(l-1)<<endl;
		}
	}
}

加上差分以后就支持区间修改,单点查询了(改两个端点就可以了)。

code:

#include<bits/stdc++.h>

using namespace std;

const int N=1e6+10;
long long c[N],a[N],n,q;
long long lowbit(int x) {return (x&-x);}
void add(int x,int v){
	while(x<=n){
		c[x]+=v;
		x+=lowbit(x);
	}
}
long long sum(int x){
	long long ans=0;
	while(x>0){
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
signed main(){
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) add(i,a[i]-a[i-1]);
	while(q--){
		int op;
		cin>>op;
		if(op==1){
			int l,r,v;
			cin>>l>>r>>v;
			add(l,v);
			add(r+1,-v);
		}else{
			int l;
			cin>>l;
			cout<<sum(l)<<endl;
		}
	}
}

但有的时候,我们既要支持区间修改,又要支持区间查询怎么办,很明显,维护两个树状数组就可以了。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N=1e6+10;
int c[N],a[N],n,q,d[N];
int lowbit(int x) {return (x&-x);}
void add(int x,int v){
	int id=x;
	while(x<=n){
		c[x]+=v;
		d[x]+=v*id;
		x+=lowbit(x);
	}
}
int sum(int x){
	int ans=0,id=x;
	while(x>0){
		ans+=(id+1)*c[x]-d[x];
		x-=lowbit(x);
	}
	return ans;
}
signed main(){
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) add(i,a[i]-a[i-1]);
	while(q--){
		int op;
		cin>>op;
		if(op==1){
			int l,r,v;
			cin>>l>>r>>v;
			add(l,v);
			add(r+1,-v);
		}else{
			int l,r;
			cin>>l>>r;
			cout<<sum(r)-sum(l-1)<<endl;
		}
	}
}
posted on 2025-08-12 19:19  hhr_qwq  阅读(6)  评论(0)    收藏  举报