树状数组区间修改区间查询

刚学的 折腾了一上午终于弄好了

树状数组几种用法(不全):
①单点修改区间查询(基本)
②区间修改单点查询(差分)
③区间修改区间查询(维护贡献)
我只特意整理了第三种用法
下方代码

#include<cstdio>
#include<iostream>
#define db delta_before
#define da delta_after
#define ll long long
using namespace std;
int n,q;
long long  a[200005],delta_before[200005],delta_after[200005];//a是原数的树状数组 da和db是维护贡献的树状数组
long long  get(ll *array,int k){
    long long  tmp=0;
    for(;k;k-=(k&-k))tmp+=array[k];
    return tmp;
}
void add(ll *array,int k,ll w){
    for(;k<=n;k+= (k&-k))array[k]+=w;

    return ;
}
long long gets(int k){
    long long ans=0;
    ans+=get(a,k);
    ans+=get(db,k);
    ans+=k*(get(da,n)-get(da,k));
    return ans;
}//gets用于取出 1到k的前缀和
void adds(int k,ll w){

    add(db,k,k*w);
    add(da,k,w);
    return ;
}//将他在前面和后面的贡献都更新
int main(){
    cin>>n>>q;
    int tmp;
    for(int i=1;i<=n;++i){
        scanf("%d",&tmp);
        for(int j=i;j<=n;j+=(j&-j))
            a[j]+=tmp;
    }
    char opt[2];int l,r;ll w;
    while(q--){

        scanf("%s%d%d",opt,&l,&r);
        if(opt[0]=='C'){

            scanf("%lld",&w); 

            adds(r,w);

            if(l>1)         //如果是0  会无限循环
            adds(l-1,-w);

        }
        else {
            ll ans1=gets(r);
            ll ans2=0;
            if(l>1) 
            ans2=gets(l-1);
            printf("%lld\n",ans1-ans2);

        }

    }

}

可以去交一下这几个板子
codevs 1082 poj 3468 luogu线段树1
因为懒就不建超链了


接下来是重头戏
二维树状数组实现矩形修改、矩形查询
著名的——上帝造题的七分钟
tyvj 1716 或者 bzoj 3132(权限题)
(不知道为什么tyvj这几天评测炒鸡慢..)
最后两个点死活过不去 在研究
先把能过八个点的代码发上来了
如下

//tyvj  1716 上帝造题的七分钟
//by  曹有毒 
#include<cstdio>
#include<iostream>
const int N=2050;
#define up(x) x+=(x&-x)
#define down(x) x-=(x&-x)
using namespace std;
int in[N][N],out[N][N],up[N][N],down[N][N];
int n,m;
int get(int array[][N],int i, int j){
    int tmp=0;

    for(int x=i;x;x-=(x&(-x)))
        for(int y=j;y;y-=(y&(-y)))
            tmp+=array[x][y];

    return tmp;
}
int getss(int x,int y){
    if(x*y==0)return 0;
    int tmp=0;
    tmp+=get(in,x,y)+x*y*(get(out,n,m)+get(out,x,y)-get(out,x,m)-get(out,n,y) );
    tmp+=y*(get(up,x,m)-get(up,x,y));
    tmp+=x*(get(down,n,y)-get(down,x,y) );
    return tmp;
}
void add(int array[][N],int x,int y,int w){
    for(int i=x;i<=n;i+=(i&(-i)))
        for(int j=y;j<=m;j+=(j&(-j)))
            array[i][j]+=w;
    return ;
}
void adds(int i,int j,int w){
    if(i*j==0)return ;
    add(in,i,j,i*j*w);
    add(down,i,j,j*w);
    add(up,i,j,i*w);
    add(out,i,j,w);
    return;
}
int main(){
    scanf("%*S%d%d",&n,&m);
    int a,b,c,d,dlt,ans;
    char opt[2];
    while( scanf("%s%d%d%d%d",opt,&a,&b,&c,&d)==5 ){
        if(opt[0]=='L'){
            scanf("%d",&dlt);
            adds(a-1,b-1,dlt);
            adds(a-1,d,-dlt);
            adds(c,b-1,-dlt);
            adds(c,d,dlt);
        }
        else {
            ans=getss(c,d)+getss(a-1,b-1)-getss(a-1,d)-getss(c,b-1);
            printf("%d\n",ans);
        }

    }
    return 0;
}

比较悲剧的 调的时候死活过不去 然后发现我分不清行和列..好多年以来一直没分清…
还是自己画个矩形推一遍式子比较好吧 根本记不住的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值