树状数组的几个模板

一:单点修改区间求和,最裸的题

题目链接:https://www.luogu.com.cn/problem/P3374

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

const int maxn=500000+10;
ll a[maxn],c[maxn];
int n,m,i,j,q,x,y,k;

void add(int i,int x){
	while (i<=n){
		c[i]+=x;i+=(i&-i);
	}
}

ll sum(int i){
    ll res=0;
	while (i>0){
		res+=c[i];i-=(i&-i);
	}
	return res;
}

int main(){
	std::ios::sync_with_stdio(false);
	cin>>n>>m;
	for (i=1;i<=n;i++){
		cin>>a[i];add(i,a[i]);
	}
	for (i=1;i<=m;i++){
		cin>>q;
		if (q==1){
			cin>>x>>k;add(x,k);
		}
		if (q==2){
			cin>>x>>y;cout<<sum(y)-sum(x-1)<<endl;
		}
	}
	return 0;
}

二:区间修改单点求和

题目链接:https://www.luogu.com.cn/problem/P3368

利用差分转化为第一种情况即可

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

const int maxn=500000+10;
ll a[maxn],c[maxn];
int n,m,i,j,k,q,x,y;

void add(int i,int x){
	while (i<=n){
		c[i]+=x;i+=(i&-i);
	}
}

ll sum(ll i){
	ll res=0;
	while (i>0){
		res+=c[i];i-=(i&-i);
	}
	return res;
}

int main(){
	std::ios::sync_with_stdio(false);
	cin>>n>>m;
	for (i=1;i<=n;i++){
		cin>>a[i];
		add(i,a[i]);add(i+1,-a[i]);
	} 
	for (i=1;i<=m;i++){
		cin>>q;
		if (q==1){
			cin>>x>>y>>k;
			add(x,k);add(y+1,-k);
		}
		if (q==2){
			cin>>x;
			cout<<sum(x)<<endl;
		}
	}
	return 0;
}

三:求逆序对

题目链接:https://vjudge.net/problem/POJ-2299

倒序扫描数组a,核心代码只有 ans+=ask(a[i]-1); add(a[i],1)。有时数据大了要离散化

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;

const int N=500010;
int c[N],a[N],x[N];
int n,i,j,k,m;

int lowbit(int y) {return y&(-y);}
void add(int x,int y) {while (x<=n){c[x]+=y; x+=lowbit(x);}}
int ask(int x){
    int res=0;
	while (x>0)	{res+=c[x]; x-=lowbit(x);}
	return res;
}

int main(){
	while (scanf("%d",&n)&&(n!=0)){
	  for (i=1;i<=n;i++) {scanf("%d",&a[i]); x[i]=a[i]; c[i]=0;}
	  sort(x+1,x+n+1); 
	  for (i=1;i<=n;i++) a[i]=lower_bound(x+1,x+n+1,a[i])-x;
	  ll ans=0;
	  for (i=n;i>=1;i--){
	  	ans+=ask(a[i]-1);
	  	add(a[i],1);
	  }
	  printf("%lld
",ans);
	}
	return 0;
}

四:二维树状数组的单点修改,区间求和

题目链接:https://vjudge.net/problem/POJ-1195

模板题。但是有一个地方一开始写错了,就是询问区域和的式子,这个以后要注意

#include<cstdio>
#include<cstring>
using namespace std;

const int N=1100;
int c[N][N],s,I,x,y,a,l,b,r,t;

int lowbit(int x){ return x&(-x);}
void add(int u,int v,int d){
	for (int i=u;i<=s;i+=lowbit(i))
	  for (int j=v;j<=s;j+=lowbit(j)) c[i][j]+=d;
}
int ask(int u,int v){
	int res=0;
	for (int i=u;i>0;i-=lowbit(i))
	  for (int j=v;j>0;j-=lowbit(j)) res+=c[i][j];
	return res;
}

int main(){
	scanf("%d",&I);
	while (I!=3){
	  if (I==0){scanf("%d",&s); memset(c,0,sizeof(c));}
	  if (I==1){
	  	scanf("%d%d%d",&x,&y,&a); x++;y++; 
		add(x,y,a);
	  }
	  if (I==2){
	  	scanf("%d%d%d%d",&l,&b,&r,&t); l++;b++;r++;t++;
	  	printf("%d
",ask(r,t)-ask(r,b-1)-ask(l-1,t)+ask(l-1,b-1));
	  }
	  scanf("%d",&I);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/edmunds/p/13620359.html