zoukankan      html  css  js  c++  java
  • 树状数组模板题 (区间查询+区间修改)

    我们知道,线段树实现区间修改和查询可以通过lazy标记来实现

    今天学到一个新姿势,树状数组也可以实现区间修改和查询

    我们引入d数组delta[i]表示区间[i, n]的共同增量 于是修改区间[l, r]时修改d[l]和d[r + 1]即可 (就是差分的思路)
    查询的时候是查询区间 [l, r] 的和 即sum[r] - sum[l - 1] 所以现在的问题是求sum[i]

    
    sum[i] = a[1]+...+a[i] + d[1]*i + d[2]*(i - 1) + d[3]*(i - 2)+...+d[i]*1   // a[i]为原始数组
            = sigma( a[x] ) + sigma( d[x]  *  (i + 1 - x) )
           = sigma( a[x] ) + (i + 1) * sigma( d[x] ) - sigma( d[x] * x )
    
    

    1
    2
    3
    其中 sigma( a[x] ) 是可以预处理出来的 于是只需要维护 d[x] 与 d[x] * x 的前缀和(作为两个树状数组就可以了)
    下面是一道板子题

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #define LL long long
    using namespace std;
    const int maxn=1e5+5;
    int n,m,x,y,v;
    LL ans;
    LL c1[maxn],c2[maxn];
    int a[maxn];
    char c;
    int lowbit(int x){
    	return x&(-x);
    }
    void update(int x,LL v){
    	for(int i=x;i<=n;i+=lowbit(i)){
    		c1[i]+=v;
    		c2[i]+=x*v;
    	}
    }
    LL query(int x){
    	LL ANS=0;
    	for(int i=x;i>0;i-=lowbit(i)){
    		ANS+=(x+1)*c1[i]-c2[i];
    	}
    	return ANS;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		update(i,a[i]-a[i-1]);
    	}
    	while(m--){
    		cin>>c; 
    		if(c=='Q'){
    			scanf("%d%d",&x,&y);
    			ans=query(y)-query(x-1);
    			printf("%lld
    ",ans);
    		}
    		if(c=='C'){
    			scanf("%d%d%d",&x,&y,&v);
    			update(x,v);update(y+1,-v);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Tomcat组件
    Tomcat介绍
    Varnish的VCL
    varnish的架构和日志
    Varnish介绍
    HAProxy的配置
    HAProxy介绍
    KeepAlived的实现示例
    KeepAlived的配置
    vue2.0填坑有感(持续更新ing)
  • 原文地址:https://www.cnblogs.com/ddddeacde/p/9984365.html
Copyright © 2011-2022 走看看