【模板篇】树状数组们(三)
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
【模板篇】树状数组们(三)相关推荐
- poj 3486 A Simple Problem with Integers(树状数组第三种模板改段求段)
1 /* 2 树状数组第三种模板(改段求段)不解释! 不明白的点这里:here! 3 */ 4 #include<iostream> 5 #include<cstring> 6 ...
- 最长上升子序列三种模板(n^2模板,二分模板,树状数组模板)
最长上升子序列(LIS)是动态规划的入门.总结下来,经常用的模板一共有三种,分别为n^2模板,二分模板,树状数组模板. n^2模板代码如下: //n^2算法,本质就是dp,采用二重循环的方式.对于数据 ...
- P3374 【模板】树状数组 1
P3374 [模板]树状数组 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示 ...
- P3374 【模板】树状数组 1( 单点修改 + 区间查询 )
题目链接:点击进入 题目 思路深入学习 树状数组实现-> 单点修改 + 区间查询 c [ i ] = a ( i - 2 ^ k + 1 ) + - + a [ i ] ( 设节点编号为 i , ...
- 洛谷P3374 【模板】树状数组 1
题目链接:[模板]树状数组 1 - 洛谷 模板题就不多说了 ac代码: #include <cstdio> #include <iostream> #include <a ...
- [P3374 【模板】树状数组 1](单点修改,区间查询)
*P3374 [模板]树状数组 1* 第一道线段树的题,很好的板子题,中文体面就不过多解释了. 直接上代码(注释很详细了,前提学过线段树) #include<bits/stdc++.h> ...
- 【模板】树状数组 2
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 洛谷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 ...
- 树状数组 java_算法模板之树状数组
什么是树状数组? 树状数组就是通过数组来模拟一种树形结构,这种树形结构能够维护区间信息.同样类似的数据结构还有线段树,线段树与树状数组相比,它的结点更多,也就是说线段树的常数更大. 线段树是通过把 ...
- 树状数组c语言模板,【树状数组】Cows (POJ2481) PASCAL 解题报告
[树状数组]Cows (POJ2481) Time Limit:1000MS Memory Limit:65536K Total Submit:16 Accepted:8 Description [问 ...
最新文章
- 岛屿类-网格类问题-DFS | 力扣695. 岛屿的最大面积
- matlab常用工具箱的调用指令
- 5g pdu session_运营商下架4G套餐,用户被5G!
- ACwing 5. 多重背包问题 II(二进制拆分+DP)
- 求解相机参数Camera Calibration
- 静态页面被拦截解决办法
- KindleConverter:Word批量转换为6寸PDF
- 将DataRow转换为DataTable
- CAD输出图至Word
- 2015阿里天池大数据竞赛解题源码
- 利用js+html做一个简单的体脂率计算
- 8m照片宽和高是多少_8寸照片的大小
- 计算机专业大学排名及本科录取分数线,计算机专业高考多少分录取?附中国计算机专业大学排名及分数线...
- post测试+php文件,PHPT – 无法运行使用–POST_RAW–的示例测试
- 用python计算工资工资_python税后工资计算器
- j2cache两级缓存框架
- 4g运行内存手机还能用多久_手机4G和6G运行内存有多大区别?看完秒懂
- 国外最受欢迎的BT-磁力网站
- 水晶报表 图表 百分比
- 14个小方法巧除鞋臭脚臭