【模板整合计划】高阶数据结构—树状数组

【模板整合计划】高阶数据结构—树状数组


一:【一维树状数组】

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]}\)

#include<cstdio>
#define LL long long
#define Re register int
const int N=5e5+3;
int n,x,y,z,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 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
*/
#include<cstdio>
#define LL long long
#define Re register int
const int N=1e6+3;
int n,x,y,z,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 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.【区间修改,单点查询】

暂时还没有找到例题。。。。

(自创样例)
输入:
2 3 8
1 1 2 2 3 2
1 1 1 2 2 -3
2 1 1
2 1 2
2 1 3
2 2 1
2 2 2
2 2 3

输出:
-3
-1
2
-3
-1
2
#include<cstdio>
#define y1 yyyy
#define LL long long
#define Re register int
const int N=4096+3;
int n,m,T,x,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 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
*/
#include<cstdio>
#define y1 yyyy
#define LL long long
#define Re register int
const int N=2048+3;
int n,m,x,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 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\)),但实战表现却比 \(ST\) 表、线段树优异。

#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));
}

-----若要转载请私信作者获得许可并在文首标出转载来源-----

posted @ 2019-10-10 10:56  辰星凌  阅读(278)  评论(0编辑  收藏  举报