【模板整合计划】高阶数据结构—树状数组
【模板整合计划】高阶数据结构—树状数组
一:【一维树状数组】
1.【单点修改,区间查询】
【模板】 树状数组 \(1\) \(\text{[P3374]}\)
【模板】 树状数组 \(1\) :单点修改,区间查询 \(\text{[Loj130]}\)
#include<cstdio>
#define LL long long
#define Re register int
const int N=5e5+3;
int n,x,y,T,op;
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
struct BIT{
LL C[N];
inline void add(Re x,Re v){while(x<=n)C[x]+=v,x+=x&-x;}
inline LL ask(Re x){LL ans=0;while(x)ans+=C[x],x-=x&-x;return ans;}
inline LL ask(Re L,Re R){return ask(R)-ask(L-1);}
}TR;
int main(){
in(n),in(T);
for(Re i=1;i<=n;++i)in(x),TR.add(i,x);
while(T--){
in(op),in(x),in(y);
if(op<2)TR.add(x,y);
else printf("%ld\n",TR.ask(x,y));
}
}
2.【区间修改,单点查询】
【模板】 树状数组 \(2\) \(\text{[P3368]}\)
【模板】 树状数组 \(2\) :区间修改,单点查询 \(\text{[Loj131]}\)
struct BIT{
LL C[N];
inline void add(Re x,Re v){while(x<=n)C[x]+=v,x+=x&-x;}
inline void add(Re L,Re R,Re v){add(L,v),add(R+1,-v);}
inline LL ask(Re x){LL ans=0;while(x)ans+=C[x],x-=x&-x;return ans;}
}TR;
int main(){
in(n),in(T);
for(Re i=1;i<=n;++i)in(x),TR.add(i,i,x);
while(T--){
in(op),in(x);
if(op<2)in(y),in(z),TR.add(x,y,z);
else printf("%lld\n",TR.ask(x));
}
}
3.【区间修改,区间查询】
【模板】 树状数组 \(3\) :区间修改,区间查询 \(\text{[Loj132]}\)
/*
n n
S[x]= (x+1)*∑A[i] - ∑i*A[i]
i=1 i=1
*/
struct BIT{
LL C1[N],C2[N];
inline void add(Re x,Re v){Re i=x;while(i<=n)C1[i]+=v,C2[i]+=(LL)x*v,i+=i&-i;}
inline void add(Re L,Re R,Re v){add(L,v),add(R+1,-v);}
inline LL ask(Re x){Re i=x;LL ans=0;while(i)ans+=(x+1)*C1[i]-C2[i],i-=i&-i;return ans;}
inline LL ask(Re L,Re R){return ask(R)-ask(L-1);}
}TR;
int main(){
in(n),in(T);
for(Re i=1;i<=n;++i)in(x),TR.add(i,i,x);
while(T--){
in(op),in(x),in(y);
if(op<2)in(z),TR.add(x,y,z);
else printf("%lld\n",TR.ask(x,y));
}
}
二:【二维树状数组】
1.【单点修改,区间查询】
【模板】 二维树状数组 \(1\):单点修改,区间查询 \(\text{[Loj133]}\)
#include<cstdio>
#define y1 yyyy
#define LL long long
#define Re register int
const int N=4096+3;
int n,m,x1,y1,x2,y2,op;
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
struct BIT{
LL C[N][N];
inline void add(Re x,Re y,Re v){
while(x<=n){Re j=y;while(j<=m)C[x][j]+=v,j+=j&-j;x+=x&-x;}
}
inline LL ask(Re x,Re y){
LL ans=0;
while(x){Re j=y;while(j)ans+=C[x][j],j-=j&-j;x-=x&-x;}
return ans;
}
inline LL ask(Re x1,Re y1,Re x2,Re y2){return ask(x2,y2)-ask(x2,y1-1)-ask(x1-1,y2)+ask(x1-1,y1-1);}
}TR;
int main(){
in(n),in(m);
while(~scanf("%d",&op)){
in(x1),in(y1),in(x2);
if(op<2)TR.add(x1,y1,x2);
else in(y2),printf("%lld\n",TR.ask(x1,y1,x2,y2));
}
}
2.【区间修改,单点查询】
#define y1 yyyy
struct BIT{
LL C[N][N];
inline void add(Re x,Re y,Re v){
while(x<=n){Re j=y;while(j<=m)C[x][j]+=v,j+=j&-j;x+=x&-x;}
}
inline void add(Re x1,Re y1,Re x2,Re y2,Re z){
add(x1,y1,z),add(x1,y2+1,-z),add(x2+1,y1,-z),add(x2+1,y2+1,z);
}
inline LL ask(Re x,Re y){
LL ans=0;
while(x){Re j=y;while(j)ans+=C[x][j],j-=j&-j;x-=x&-x;}
return ans;
}
}TR;
int main(){
in(n),in(m),in(T);
while(T--){
in(op),in(x1),in(y1);
if(op<2)in(x2),in(y2),in(x),TR.add(x1,y1,x2,y2,x);
else printf("%lld\n",TR.ask(x1,y1));
}
}
3.【区间修改,区间查询】
【模板】 二维树状数组 \(3\):区间修改,区间查询 \(\text{[Loj135]}\)
/*
n m n m n m n m
s[x][y]=(x+1)*(y+1)*∑ ∑a[i][j] - (y+1)*∑ ∑a[i][j]*i - (x+1)*∑ ∑a[i][j]*j + ∑ ∑a[i][j]*i*j
i=1 j=1 i=1 j=1 i=1 j=1 i=1 j=1
*/
struct BIT{
LL C1[N][N],C2[N][N],C3[N][N],C4[N][N];
inline void add(Re x,Re y,Re v){
Re i=x;
while(i<=n){
Re j=y;
while(j<=m)C1[i][j]+=v,C2[i][j]+=(LL)x*v,C3[i][j]+=(LL)y*v,C4[i][j]+=(LL)x*y*v,j+=j&-j;
i+=i&-i;
}
}
inline void add(Re x1,Re y1,Re x2,Re y2,Re z){
add(x1,y1,z),add(x1,y2+1,-z),add(x2+1,y1,-z),add(x2+1,y2+1,z);
}
inline LL ask(Re x,Re y){
Re i=x;LL ans=0;
while(i){
Re j=y;
while(j)ans+=(LL)(x+1)*(y+1)*C1[i][j]-(LL)(y+1)*C2[i][j]-(LL)(x+1)*C3[i][j]+C4[i][j],j-=j&-j;
i-=i&-i;
}
return ans;
}
inline LL ask(Re x1,Re y1,Re x2,Re y2){
return ask(x2,y2)-ask(x2,y1-1)-ask(x1-1,y2)+ask(x1-1,y1-1);
}
}TR;
int main(){
in(n),in(m);
while(~scanf("%d",&op)){
in(x1),in(y1),in(x2),in(y2);
if(op<2)in(x),TR.add(x1,y1,x2,y2,x);
else printf("%lld\n",TR.ask(x1,y1,x2,y2));
}
}
三:【单点修改,区间查询(最大值)】
【模板】 \(\text{ST}\) 表 \(\text{[P3865]}\)
【模板】 \(\text{I}\) \(\text{Hate}\) \(\text{It}\) \(\text{[P1531]}\) \(\text{[Hdu1754]}\)
虽然理论时间复杂度较高(\(\log^2n\)),但实战表现却比线段树优异。
#include<cstdio>
#define LL long long
#define Re register int
const int N=1e5+3;
int n,x,y,T,A[N];
inline void in(Re &x){
int f=0;x=0;char ch=getchar();
while(ch<'0'||ch>'9')f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=f?-x:x;
}
inline int max(Re a,Re b){return a>b?a:b;}
struct BIT{
int C[N];
inline void add(Re x,Re v){while(x<=n)C[x]=max(C[x],v),x+=x&-x;}
inline int ask(Re l,Re r){
Re ans=0;
while(l<=r){
while(r-(r&-r)>=l)ans=max(ans,C[r]),r-=r&-r;
ans=max(ans,A[r--]);
}
return ans;
}
}TR;
int main(){
in(n),in(T);
for(Re i=1;i<=n;++i)in(A[i]),TR.add(i,A[i]);
while(T--)in(x),in(y),printf("%d\n",TR.ask(x,y));
}