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

    前言

    某5机房最最最弱的菜鸡,在gm突击测验树状数组版题的时候,居然忘记了如何打区间修改,区间查询(出生不带脑子名副其实

    然后他抱着疑问的心态打开了自己之前关于树状数组的blog,发现他之前写了个什么玩意

    再仔细回想了一下思想发现自己并没有真正理解,于是也就有了为什么暑假学的东东现在还写blog。毕竟学习不求甚解是不可取的(突然讲起了大道理

    题目

    给定数列 $a[1],a[2], ldots , a[n] $,你需要依次进行 个操作,操作有两类:

    • 1 l r x:给定 (l, r, x),对于所有 (i /in [l, r]),将 (a[i]) 加上 (x)(换言之,将 $a[l],a[l + 1], ldots , a[r] $ 分别加上 (x));
    • 2 l r:给定(l, r) ,求(sum_{i = l}^{r} a[i]) 的值(换言之,求(a[l]+a[l + 1]+ ldots + a[r]) 的值)。

    思路&&推导过程

    前置知识(特别水)

    在有了前置知识(丝毫不心虚),我们就可以知道,如何单点修改,区间查询和 如何区间修改,单点查询了。

    在区间修改,单点查询中知道了我们可以用差分来实现区间修改。而第(i)个数用差分表示应该是(sum[1] + sum[2] +ldots + sum[i])

    那么第1个数到第(i)个数, 该如何用一串差分表示呢?

    ((sum[1]) + (sum[1] + sum[2]) + ldots + (sum[1] + sum[2] +ldots + sum[i]))

    于是乎,用笔者那本就不存在的脑子想了一想:

    我们就枚举每一个数再求(sum)不香吗?但笔者立马否定了这个想法,毕竟(O(n imes n imes log_{n}))真的很惊悚。。。

    我们再回到这个式子

    ((sum[1]) + (sum[1] + sum[2]) + ldots + (sum[1] + sum[2] +ldots + sum[i]))

    (= sum[1] * i + sum[2] * (i - 1) + ldots + sum[i] * (i - i + 1))

    (= (sum[1] + sum[2] +ldots + sum[i]) imes i - ((sum[1] imes (1 - 1) + (sum[1] imes (1 - 1) + ldots + sum[i] imes (i - 1))

    于是大师我悟了!:
    ((sum[1] + sum[2] +ldots + sum[i])) 不就是用区间修改区间查询就可以解决了吗?

    ((sum[1] imes (1 - 1) + (sum[1] imes (1 - 1) + ldots + sum[i] imes (i - 1))我们就用另一个(Update)来存就行了

    于是代码就很快乐的打出来了!(改改就能用

    AC代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn = 1e6 + 5;
    
    int  n, q;
    int a[maxn];
    int sum[maxn];
    long long BIT[maxn], BIT2[maxn];
    
    int Lowbit(int a){
    	return a & (-a);
    }
    
    void Update(int x, int k){
    	for(int i = k; i <= n; i += Lowbit(i)){
    		BIT[i] += x;
    	}
    }
    
    void Update2(int x, int k){
    	for(int i = k; i <= n; i += Lowbit(i)){
    		BIT2[i] += (long long)x * (k - 1);
    	}
    }
    
    long long Sum(int x){
    	long long ans = 0;
    	for(int i = x; i > 0; i -= Lowbit(i)){
    		ans += BIT[i];
    	}
    	return ans;
    }
    
    long long Sum2(int x){
    	long long ans = 0;
    	for(int i = x; i > 0; i -= Lowbit(i)){
    		ans += BIT2[i];
    	}
    	return ans;
    }
    
    int main() {
    	scanf("%d %d", &n, &q);
    	for(int i = 1; i <= n; i ++){
    		scanf("%d", &a[i]);
    		sum[i] = a[i] - a[i - 1];
    		Update(sum[i], i);
    		Update2(sum[i], i);
    	}
    	for(int i = 1; i <= q; i ++){
    		int flag;
    		scanf("%d", &flag);
    		if(flag == 1){
    			int x, l, r;
    			scanf("%d %d %d", &l, &r, &x);
    			Update(x, l);
    			Update(-x, r + 1);
    			Update2(x, l);
    			Update2(-x, r + 1);
    		}
    		else{
    			int l, r;
    			scanf("%d %d", &l, &r);
    			printf("%lld
    ", (r * Sum(r) - Sum2(r)) - ((l - 1) * Sum(l - 1) - Sum2(l - 1))); 
    		} 
    	}
    	return 0;
    } 
    

    参考资料(特别鸣谢orz)

    https://blog.csdn.net/qq_43398760/article/details/93776758

    夜空中最亮的星,请照亮我前行
  • 相关阅读:
    使用TFS CI 又想保留服务运行状态的简单方法
    【知乎】二战中日本陆军的建制
    缓存你的BITMAP对象
    Android 多种方式正确的加载图像,有效避免oom
    GitHub进一步了解
    响应式编程,是明智的选择
    Android 主题动态切换框架:Prism
    Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误
    ClassLoader工作机制
    Java——泛型(最易懂的方式讲解泛型)
  • 原文地址:https://www.cnblogs.com/Nefelibata/p/14013204.html
Copyright © 2011-2022 走看看