树状数组

基本用途:维护序列的前缀和。

对于给定的序列a,我们建立一个数组c,其中从c[x]保存序列a的区间[x-lowbit(x)+1,x]中所有数的和。

数组c可以看作一个如下图所示的树形结构:

图中最下边一行是n个节点,代表数值a[1~n]。该结构满足以下性质:

  • 每个内部节点c[x]保存以它为根的子树中所有叶节点的和;
  • 每个内部节点c[x]的子节点个数=lowbit(x)的位数;
  • 除树根外,每个内部节点c[x]的父节点是c[x+lowbit(x)];
  • 树的深度为O(logn)。

1.单点修改,区间查询

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[155000],c[155000];
int lowbit(int x){
	return x&-x;
}
void add(int x,int key){
	while(x<=n){
		c[x]+=key;
		x+=lowbit(x);
	}
}
int getsum(int x){
	int res=0;
	while(x){
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		add(i,a[i]);
	}
	scanf("%d",&m);
    string str;
	int x,y;
	for(int i=1;i<=m;i++){
		cin>>str>>x>>y;
		if(str[0]=='S'){
			printf("%d\n",getsum(y)-getsum(x-1));
		}
		else{
			add(x,y);
		}
	}
	return 0;
} 

2.区间修改,单点查询

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[155000],c[155000];
int lowbit(int x){
	return x&-x;
}
void add(int x,int key){
	while(x<=n){
		c[x]+=key;
		x+=lowbit(x);
	}
}
int getsum(int x){
	int res=0;
	while(x){
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		add(i,a[i]-a[i-1]);
	}
	scanf("%d",&m);
    string str;
	int x,y,z;
	for(int i=1;i<=m;i++){
		cin>>str;
		if(str[0]=='Q'){
		    cin>>x;
			printf("%d\n",getsum(x));
		}
		else{
			cin>>x>>y>>z;
			add(x,z);
			add(y+1,-z);
		}
	}
	return 0;
}

3.区间修改,区间查询

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long a[155000],c1[155000],c2[155000];
long long lowbit(int x){
	return x&-x;
}
void add(int x,int key){
	long long tmp=x;
	while(x<=n){
		c1[x]+=key;
		c2[x]+=(long long)tmp*key;
		x+=lowbit(x);
	}
}
long long getsum(int x){
	long long ans=0,tmp=x;
	while(x){
		ans+=c1[x]*(tmp+1)-c2[x];
		x-=lowbit(x);
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		add(i,a[i]-a[i-1]);
	}
	scanf("%d",&m);
    string str;
	int x,y,z;
	for(int i=1;i<=m;i++){
		cin>>str;
		if(str[0]=='S'){
		    cin>>x>>y;
			printf("%lld\n",getsum(y)-getsum(x-1));
		}
		else{
			cin>>x>>y>>z;
			add(x,z);
			add(y+1,-z);
		}
	}
	return 0;
}

 

posted on 2024-02-19 08:40  风ffff  阅读(10)  评论(0编辑  收藏  举报