UPD: 本篇有了一个更通(hui)俗(se)易(nan)懂的讲解, 大家可以移步这里围观~(使用了latex推柿子, 带给你不一样的清新体验~

ok,以上两期稍稍讲了一下树状数组的基本功能。。

  • 最最基础——单点加,区间查 http://blog.csdn.net/enzymii/article/details/54952957 忘了的回去看哦
  • 升级做法——区间加,单点查 http://blog.csdn.net/enzymii/article/details/54965280

当然,把树状数组拉出来不能只有这两个功能对不对。。。(不然网上都有怎么把你们忽悠来看嘛)
树状数组还是有两把刷子的

(非战斗人员退散)
今天,我们要讲的是:

区间加,区间查

什么???
许多学过线段树的人该诧异了吧。。
树状数组还能干这事?
答案是可以的。。
(○| ̄|_在此%拜一下发明这种做法的神犇orz)

还记得上次我们的c变化成了差分数组吗?
树状数组就是擅长求前缀和和维护差分信息~
当然,这次的目标中有两个区间字样,所以要开两个数组(什么逻辑嘛……)

其实原因并不是这样。

我们用一个差分数组来保存相邻两个数据的差,这个数组命名为c1
此时,无论我们在树状数组上怎么乱搞,原数据的第i个点最后的值(记为a[i]吧)就是求一下c1[i]的总和
(嗯我们上一期的单点查)
对于区间修改,我们采取让c1[l]加和让c1[r+1]减的方式(还是差分)
对于区间查询,我们有ans=sum[r]-sum[l-1](How old are you,差分?)
于是很明显,最后原数组中第i个点乱搞一波后的值是sigma(c1[j]) (j=1..i)

你们理清楚没有。。

理清楚之后,
求1~i的和的时候,仔细看下面:

sum(i)=a[1]+a[2]+...+a[i]=c1[1]+(c1[1]+c1[2])+...+(c1[1]+c1[2]+...+c1[i])=i*c1[1]+(i-1)*c1[2]+...+1*c1[i]=i*(c1[1]+c1[2]+...+c1[i])-(0*c1[1]+1*c1[2]+...+(i-1)*c1[i])=i*sigma(c1[j])-sigma(c1[j]*(j-1)) (j=1..i)

所以,我们只要同时 维护一下sigma(c1[j])和sigma(c1[j]*(j-1))就行了。。
还记得c1的差分性质么
所以我们再用一个数组c2搞出sigma(c1[j]*(j-1)),在维护c1的时候顺手维护一下即可。。
这样复杂度也不会被改变!!!非常好而且奇妙的性质。。。
sum[i]就照着上面的式子搞就行。。

下面,终于到了代码,我有一件事情要说:其实只看代码就好,上面讲的没啥用233
代码的例子是用的luogu3372的【模板】线段树 1 (哈哈哈哈,用线段树的人们!)
题目传送门:
https://www.luogu.org/problem/show?pid=3372
里面的数据是要用long long的。。
你们自己看情况改就好了233
而且听说codevs1082的线段树练习3也可以用这种方法水过。。
这题的传送门:http://www.codevs.cn/problem/1082/
而且码长空间时间都要优于线段树哦。。

不过main函数我就不写了_ (:з」∠) _
而且这两个题都要开long long而代码里是没有开的

#include <cstdio>#define gc getcharint getnum() {int a = 0; char c = gc(); bool f = 0;for (; (c<'0' || c>'9') && c != '-'; c = gc());if (c == '-') f = 1, c = gc();for (; c >= '0'&&c <= '9'; c = gc()) a = (a << 1) + (a << 3) + c - '0';return f ? -a : a;
}class Binary_Tree3 {private:static const int MAXN = 200002;int c1[MAXN], c2[MAXN], n, a[MAXN];inline int lb(int x) {return x&-x;}int getnum() {int a = 0; char c = gc(); bool f = 0;for (; (c<'0' || c>'9') && c != '-'; c = gc());if (c == '-') f = 1, c = gc();for (; c >= '0'&&c <= '9'; c = gc()) a = (a << 1) + (a << 3) + c - '0';return f ? -a : a;}
public:void build(int sum) {n = sum;for (int i = 1; i <= sum; i++) {a[i] = getnum();add(c1, i, a[i] - a[i - 1]);add(c2, i, (i - 1) * (a[i] - a[i - 1]));}}void add(int *r, int x, int i) {for (; x <= n; x += lb(x))r[x] += i;}int ask(int *r, int x) {int s = 0;for (; x; x -= lb(x))s += r[x];return s;}void adda(int l, int r, int i) {add(c1, l, i); add(c1, r + 1, -i);add(c2, l, i * (l - 1)); add(c2, r + 1, -i * r);}int query(int l, int r) {return r * ask(c1, r) - ask(c2, r) - (l - 1) * ask(c1, l - 1) + ask(c2, l - 1);}};

大概就是这个样子了。。
- 区间加的话就调用adda(l,r,i)就是区间[l,r]加i
- 区间查的话就输出query(l,r)就是区间[l,r]的区间和了。。
对就是这样。

转载于:https://www.cnblogs.com/enzymii/p/8412157.html

【模板篇】树状数组们(三)相关推荐

  1. poj 3486 A Simple Problem with Integers(树状数组第三种模板改段求段)

    1 /* 2 树状数组第三种模板(改段求段)不解释! 不明白的点这里:here! 3 */ 4 #include<iostream> 5 #include<cstring> 6 ...

  2. 最长上升子序列三种模板(n^2模板,二分模板,树状数组模板)

    最长上升子序列(LIS)是动态规划的入门.总结下来,经常用的模板一共有三种,分别为n^2模板,二分模板,树状数组模板. n^2模板代码如下: //n^2算法,本质就是dp,采用二重循环的方式.对于数据 ...

  3. P3374 【模板】树状数组 1

    P3374 [模板]树状数组 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示 ...

  4. P3374 【模板】树状数组 1( 单点修改 + 区间查询 )

    题目链接:点击进入 题目 思路深入学习 树状数组实现-> 单点修改 + 区间查询 c [ i ] = a ( i - 2 ^ k + 1 ) + - + a [ i ] ( 设节点编号为 i , ...

  5. 洛谷P3374 【模板】树状数组 1

    题目链接:[模板]树状数组 1 - 洛谷 模板题就不多说了 ac代码: #include <cstdio> #include <iostream> #include <a ...

  6. [P3374 【模板】树状数组 1](单点修改,区间查询)

    *P3374 [模板]树状数组 1* 第一道线段树的题,很好的板子题,中文体面就不过多解释了. 直接上代码(注释很详细了,前提学过线段树) #include<bits/stdc++.h> ...

  7. 【模板】树状数组 2

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  8. 洛谷P3368 【模板】树状数组 2(Python和C++代码)

    ##就是常规写法 用树状数组维护一个差分数组的前缀和,因为可推得若b[i]=a[i]-a[i-1],则a[i]=b[1]+-+b[i] (b[1]=a[1]-a[0],a[0]=0) . 可发现a[i ...

  9. 树状数组 java_算法模板之树状数组

    什么是树状数组? ​树状数组就是通过数组来模拟一种树形结构,这种树形结构能够维护区间信息.同样类似的数据结构还有线段树,线段树与树状数组相比,它的结点更多,也就是说线段树的常数更大. ​线段树是通过把 ...

  10. 树状数组c语言模板,【树状数组】Cows (POJ2481) PASCAL 解题报告

    [树状数组]Cows (POJ2481) Time Limit:1000MS Memory Limit:65536K Total Submit:16 Accepted:8 Description [问 ...

最新文章

  1. 岛屿类-网格类问题-DFS | 力扣695. 岛屿的最大面积
  2. matlab常用工具箱的调用指令
  3. 5g pdu session_运营商下架4G套餐,用户被5G!
  4. ACwing 5. 多重背包问题 II(二进制拆分+DP)
  5. 求解相机参数Camera Calibration
  6. 静态页面被拦截解决办法
  7. KindleConverter:Word批量转换为6寸PDF
  8. 将DataRow转换为DataTable
  9. CAD输出图至Word
  10. 2015阿里天池大数据竞赛解题源码
  11. 利用js+html做一个简单的体脂率计算
  12. 8m照片宽和高是多少_8寸照片的大小
  13. 计算机专业大学排名及本科录取分数线,计算机专业高考多少分录取?附中国计算机专业大学排名及分数线...
  14. post测试+php文件,PHPT – 无法运行使用–POST_RAW–的示例测试
  15. 用python计算工资工资_python税后工资计算器
  16. j2cache两级缓存框架
  17. 4g运行内存手机还能用多久_手机4G和6G运行内存有多大区别?看完秒懂
  18. 国外最受欢迎的BT-磁力网站
  19. 水晶报表 图表 百分比
  20. 14个小方法巧除鞋臭脚臭

热门文章

  1. 如何让地面不起灰_水泥地面起灰怎么办?
  2. react classname多个_React全家桶简介
  3. java 字符串 移位_算法学习之字符串左移和右移
  4. python ls_linux 常用shell命令 ls
  5. 递归实现组合型枚举(搜索)
  6. python 下采样和上采样
  7. 加速网站速度的最佳做法_(2)把样式表放在顶部
  8. 阿里要把雄安打造成AI第一城:未来30年城市长啥样?
  9. Linux基础-固化命令的方式grep
  10. OC-内存管理的一些要点