树状数组的几个模板
一:单点修改区间求和,最裸的题
题目链接: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\n",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\n",ask(r,t)-ask(r,b-1)-ask(l-1,t)+ask(l-1,b-1));
}
scanf("%d",&I);
}
return 0;
}

浙公网安备 33010602011771号