树状数组

文章目录

  • 一、单点修改+区间和查询
  • 二、单点查询+区间修改
  • 三、单点修改+区间修改+区间和查询
  • 四、区间最值查询
  • 五、二维情况下的树状数组

一、单点修改+区间和查询

#include
using namespace std;
int n,m,i,num[100001],t[200001],l,r;//num:原数组;t:树状数组
 
int lowbit(int x)
{
    return x&(-x);
}
 
void change(int x,int p)//将第x个数加p 
{
    while(x<=n)
    {
        t[x]+=p;
        x+=lowbit(x);
    }
    return;
}
 
int sum(int k)//前k个数的和 
{
    int ans=0;
    while(k>0)
    {
        ans+=t[k];
        k-=lowbit(k);
    }
    return ans;
}
 
int ask(int l,int r)//求l-r区间和 
{
    return sum(r)-sum(l-1); 
}
 
int main()
{
    cin>>n>>m;
    for(i=1;i<=n;i++)
    {
        cin>>num[i];
        change(i,num[i]);
    }
    for(i=1;i<=m;i++)
    {
        cin>>l>>r;
        cout<<ask(l,r)<<endl;
    }
    return 0;
}

二、单点查询+区间修改

a[]原数组 d[]差分数组,即d[i]=a[i]-a[i-1]

易得a[i]=d1+d2+d3+…+di

当需要将[l,r]内的元素都加上x时,由于d是差分数组,因此只需将d[l]+x,d[r+1]-x即可

使用树状数组维护d数组即可快速实现单点查询和区间修改操作

//区间修改时修改d[l]和d[r+1]的值 
void change(int x,int p)
{
	while(x<n){
		d[x]+=p;
		x+=lowbit(x);
	}
}
 
//区间修改 ,使区间[l,r]的数加上x->只需使d[l]+x,d[r+1]-x即可  
void update(int l,int r,int p)
{
	change(l,x);
	change(r+1,-x);
}
 
//单点查询,查询x位置的值 
int getvalue(int x)
{
	int p=0;
	while(x>0){
		sum+=d[x];
		x-=lowbit(x);
	}
	return p;
}

三、单点修改+区间修改+区间和查询

a[]原数组 d[]差分数组,即d[i]=a[i]-a[i-1]

易得a[i]=d1+d2+d3+…+di

设sum(1,k)表示a1+a2+a3+…+ak

那么sum(1,k)=d1 + (d1+d2) + (d1+d2+d3) + … + (d1+d2+d3+…+dk)=k*(d1+d2+d3+…+dk) - (0d1 + 1d2 + 2*d3 +…+ (k-1)*dk)

因此可以用树状数组维护两个数组d1[],d2[]即可,d1[]维护di,d2[]维护(i-1)*di

int a[N],d1[N],d2[N];//a原数组 d1 d2树状数组 
 
void change(int t[],int x,int p)
{
	while(x<n){
		t[x]+=p;
		x+=lowbit(x);
	}
}
 
//区间修改 区间[l,r]内的数加上p 
void update(int l,int r,int p)
{
	//d1数组 
	change(d1,l,p);
	change(d1,r+1,-p);
	//d2数组
	change(d2,l,(l-1)*p);
	change(d2,r+1,-r*p);
}
 
int getsum(int t[],int x) 
{
	int val=0;
	while(x>0){
		val+=t[x];
		x-=lowbit(x);
	} 
	return val;
}
 
//计算a1+a2+...+an的和 
int sum(int x) 
{
    int ans1,ans2;
    ans1=x*getsum(d1,x);
    ans2=getsum(d1,x);
    return ans1-ans2;
}
 
//区间和查询 ,计算区间[l,r]内的元素和 
int query(int l,int r)
{
	return sum(r)-sum(l-1); 
}

四、区间最值查询

int a[N],t[N];//a[] 原数组 t[]树状数组 
 
//单点更新
void update(int x)
{
	while(x<=n){
		t[x]=a[x];
		int len=lowbit(x);
		for(int i=1;i<len;i<<=1)
		  t[x]=max(t[x],t[x-i]);
		x+=lowbit(x);
	}
}
 
//区间最值查询 查询区间[l,r]的最值 
int query(int l,int r)
{
	int ans=0;
	while(r>=l){
		ans=max(a[r],ans);
		r--;
		while(r-lowbit(r)>=x){
			ans=max(t[r],ans);
			r-=lowbit(r);
		}
	}
	return ans;
} 
 

五、二维情况下的树状数组

单点修改+区间和查询

//单点修改 
void change(int x,int y,int p)
{
	for(int i=x;i<=n;i+=lowbit(i))
	  for(int j=y;j<=n;j+=lowbit(j))
	    t[i][j]+=p;		
}
 
//区间查询
int query(int x,int y)
{
	int ans=0;
	for(int i=x;i>=0;i-=lowbit(i))
	  for(int j=y;j>=0;j-=lowbit(j))
	    ans+=t[i][j];
	return ans;
} 

你可能感兴趣的:(数据结构)