【数据结构】树状数组【模板】

证明什么的待补

一维

问题 E: 单点修改,区间查询

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long  ll;
const int N=1e6+7;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll a[N],c[N],n;
inline int lowbit(int x){
    return x&-x;
}
inline void add(int i,int x){
    while(i<=n){
        c[i]+=x;
        i+=lowbit(i);
    }
    return ;
}
inline ll  sum(int i){
    ll  res=0;
    while(i){
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}
int main(){
    int q;
    n=read();q=read();
    for(int i=1;i<=n;i++){
        int x;
        x=read();
        add(i,x);
    }
    while(q--){
        int l,r,w;
        w=read();l=read();r=read();
        if(w==1) add(l,r);
        else {
                ll res=sum(r)-sum(l-1);
                printf("%lld\n",res);
        }
    }
    return 0;
}

问题 F: 区间修改,单点查询

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+7;
ll a[N],c[N];//原数组和树状数组
ll n;
inline ll read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline ll lowbit(ll x){
    return x&-x;
}
void add(ll i,ll k){
    while(i<=n){
        c[i]+=k;
        i+=lowbit(i);
    }
}
ll sum(ll i){//求a[1]到a[n]的和
    ll res=0;
    while(i>0){
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}
int main(){
    ll q,x;
    n=read();q=read();
    for(ll i=1;i<=n;i++){
        a[i]=read();
        add(i,a[i]-a[i-1]);
    }
 
    while(q--){
        ll a,b,c,d;
        a=read();
        if(a==1){
           b=read();c=read();d=read();
            add(b,d);
            add(c+1,-d);
        }
        else{
           b=read();
            printf("%lld\n",sum(b));
        }
    }
    return 0;
}

问题 G: 区间修改,区间查询

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+7;
ll a[N],sum1[N],sum2[N];
ll n,m;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline ll lowbit(ll x){
    return x&-x;
}
inline void update(ll i,ll k){
    ll x=i;
    while(i<=n){
        sum1[i]+=k;
        sum2[i]+=k*(x-1);
        i+=lowbit(i);
    }
}
inline ll sum(int i){
    ll res=0,x=i;
    while(i>0){
        res+=x*sum1[i]-sum2[i];
        i-=lowbit(i);
    }
    return res;
}
int main(){
    n=read();m=read();
    for(ll i=1;i<=n;i++){
        cin>>a[i];
        update(i,a[i]-a[i-1]);
    }
    while(m--){
        ll k,l,r,x;
        k=read();
        if(k==1){
            l=read();r=read();x=read();
            update(l,x);
            update(r+1,-x);
        }
        else{
            l=read();r=read();
            ll res=sum(r)-sum(l-1);
            printf("%lld\n",res);
        }
    }
    return 0;
}

二维

问题 H: 单点修改,区间查询

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5500;
ll a[N][N],n,m;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll lowbit(ll x){
    return x&-x;
}
void update(ll x,ll y,ll v){
    for(int i=x;i<=n;i+=lowbit(i))
        for(int j=y;j<=m;j+=lowbit(j))
            a[i][j]+=v;
}
ll sum(ll x,ll y){
    ll res=0;
    for(int i=x;i>0;i-=lowbit(i))
        for(int j=y;j>0;j-=lowbit(j))
            res+=a[i][j];
    return res;
}
ll query(ll x1,ll y1,ll x2,ll y2){
    return sum(x1,y1)-sum(x1,y2-1)-sum(x2-1,y1)+sum(x2-1,y2-1);
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        memset(a,0,sizeof a);
        int op;
        while(~scanf("%d",&op)){
            if(op==1){
                ll x,y,k;
                x=read();y=read();k=read();
                //cin>>x>>y>>k;
                update(x,y,k);
            }
            else{
                ll a,b,c,d;
                c=read();d=read();a=read();b=read();
                //cin>>a>>b>>c>>d;
                printf("%lld\n",query(a,b,c,d));
            }
        }
    }
    return 0;
}

问题 I: 区间修改,区间查询

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2100;
ll t1[N][N],t2[N][N],t3[N][N],t4[N][N];
ll n,m;
ll lowbit(ll x){
    return x&(-x);
}
void add(ll x,ll y,ll v){
    for(ll i=x;i<=n;i+=lowbit(i))
        for(ll j=y;j<=m;j+=lowbit(j)){
            t1[i][j]+=v;
            t2[i][j]+=v*x;
            t3[i][j]+=v*y;
            t4[i][j]+=v*x*y;
        }
}
void update(ll x1,ll y1,ll x2,ll y2,ll v){
    add(x1,y1,v);
    add(x1,y2+1,-v);
    add(x2+1,y1,-v);
    add(x2+1,y2+1,v);
}
ll sum(ll x,ll y){
    ll res=0;
    for(ll i=x;i>0;i-=lowbit(i))
        for(ll j=y;j>0;j-=lowbit(j))
            res+=(x+1)*(y+1)*t1[i][j]-(y+1)*t2[i][j]-(x+1)*t3[i][j]+t4[i][j];
    return res;
}
ll query(ll x1,ll y1,ll x2,ll y2){
    return sum(x2,y2)+sum(x1-1,y1-1)-sum(x2,y1-1)-sum(x1-1,y2);
}
int main(){
    scanf("%lld%lld", &n, &m);
    int op;
    while(~scanf("%d",&op)){
        if(op==1){
            ll a,b,c,d,x;
             scanf("%lld%lld%lld%lld%lld", &a, &b, &c, &d, &x);
           // a=read();b==read();c=read();d=read();x=read();
            update(a,b,c,d,x);
        }
        else{
            ll a,b,c,d;
             scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
            //a=read();b==read();c=read();d=read();
            printf("%lld\n",query(a,b,c,d));
        }
    }
    return 0;
}

参考博客:树状数组详解 - Xenny - 博客园 (吹爆这篇!)
彻底弄懂二维树状数组_ó-CSDN博客
二维树状数组总结及模板_kangdi的博客-CSDN博客

posted @ 2020-01-31 12:38  OvO1  阅读(54)  评论(0编辑  收藏  举报