首页 > 其他分享 >超级树状数组

超级树状数组

时间:2024-09-16 15:54:48浏览次数:8  
标签:dj limits 树状 int 超级 lint 数组 sum

众所周知:

  • 线段树的代码长,常数大;
  • 树状数组的代码短,常数小,甚至可以通过 1 0 6 10^6 106 量级的数据。

所以,能不能实现一个可以区间修改、区间查询的树状数组呢?


由于涉及区间操作,考虑差分数组 { d n } \{d_n\} {dn​}。

区间修改

对于原数组 [ l , r ] [l,r] [l,r] 区间每个数加 w w w。

可以转化为两次单点修改,即 l l l 单点处加 + w +w +w, r + 1 r+1 r+1 单点处加 − w -w −w。

区间查询

对于原数组 [ l , r ] [l,r] [l,r] 区间求和。

显然 ∑ i = l r a i \sum\limits_{i=l}^r a_i i=l∑r​ai​ 可以差分为两个 [ 1 , u ] [1,u] [1,u] 的前缀求和。

∑ i = 1 u a i = ∑ i = 1 u ∑ j = 1 i d j \sum\limits_{i=1}^{u} a_i =\sum\limits_{i=1}^u\sum\limits_{j=1}^{i}d_j i=1∑u​ai​=i=1∑u​j=1∑i​dj​

观察每一个 a i = ∑ j = 1 i d j a_i=\sum\limits_{j=1}^{i}d_j ai​=j=1∑i​dj​,可以发现

a 1 = d 1 a 2 = d 1 + d 2 a 3 = d 1 + d 2 + d 3 ⋯ a u = d 1 + d 2 + d 3 + ⋯ + d u \begin{aligned} a_1&=d_1\\ a_2&=d_1+d_2\\ a_3&=d_1+d_2+d_3\\ \cdots\\ a_u&=d_1+d_2+d_3+\cdots+d_u \end{aligned} a1​a2​a3​⋯au​​=d1​=d1​+d2​=d1​+d2​+d3​=d1​+d2​+d3​+⋯+du​​

所以 d 1 d_1 d1​ 的贡献为 u u u, d 2 d_2 d2​ 的贡献为 u − 1 u-1 u−1, d 3 d_3 d3​ 的贡献为 u − 2 u-2 u−2,……, d u d_u du​ 的贡献为 1 1 1。

故可得 d k d_k dk​ 的贡献为 u − j + 1 u-j+1 u−j+1。

∑ i = 1 u ∑ j = 1 i d j = ∑ j = 1 u d j ( u − j + 1 ) \sum\limits_{i=1}^u\sum\limits_{j=1}^{i}d_j=\sum\limits_{j=1}^{u}d_j(u-j+1) i=1∑u​j=1∑i​dj​=j=1∑u​dj​(u−j+1)

发现 u + 1 u+1 u+1 的值是固定的,可以提取出来:

∑ j = 1 u d j ( u − j + 1 ) = ( ( u + 1 ) ∑ j = 1 u d j ) − ( ∑ j = 1 u ( j × d j ) ) \sum\limits_{j=1}^{u}d_j(u-j+1)=\Big((u+1)\sum\limits_{j=1}^{u}d_j\Big)-\Big(\sum\limits_{j=1}^{u}(j\times d_j)\Big) j=1∑u​dj​(u−j+1)=((u+1)j=1∑u​dj​)−(j=1∑u​(j×dj​))

因此同时使用两个树状数组维护 { d n } \{d_n\} {dn​}、 { n × d n } \{n\times d_n\} {n×dn​} 即可,该技巧即为超级树状数组。

代码实现

typedef long long lint;
lint sum(int p, lint *t) { // 查询 t 中 [1,p] 之和
	lint res = 0;
	for (int i = p; i; i -= lowbit(i))
		res += t[i];
	return res;
}

lint ask(int p) {
	return sum(p, d) * (p + 1) - sum(p, f);
}

lint query(int l, int r) {
	return ask(r) - ask(l - 1);
}

void add(int p, lint x, lint *t) {
	for (int i = p; i <= n; i += lowbit(i)) t[i] += x;
}

void update(int l, int r, lint x) {
	add(l, x, d), add(r + 1, -x, d);
	add(l, x * l, f);
	add(r + 1, -x * (r + 1), f);
}

标签:dj,limits,树状,int,超级,lint,数组,sum
From: https://blog.csdn.net/OIer_wst/article/details/142303421

相关文章

  • C语言中的GCC的优化和数组的存放方式、Cache机制、访问局部性
    “我们仍需共生命的慷慨与繁华相爱,即使岁月以刻薄和荒芜相欺”文章目录前言文章有误敬请斧正不胜感恩!第一题:***什么是gcc:***C语言中,“gcc-O2”是使用GCC编译器时的一个编译选项。第一部分:为什么程序一输出0,而程序二输出1?第二题:第二部分:为什么两个循环版本的性能......
  • 多维数组
    1.定义以二维数组为例,即一个大数组里面包含了无数个小数组,只不过大数组里面的不再是数,而是数组,而小数组里面的是数字定义了一个二维数组arr[][]其中有三个小数组,三个小数组中存在数字2.语法3.实操4.输出所有数先定义一个二维数组,然后使用第一次for循环让二维数组输出,接......
  • 代码随想录算法训练营Day5 | 哈希表理论基础、242.有效的字母异位词、349.两个数组的
    哈希表理论基础哈希表哈希表是根据关键码的值而直接进行访问的数据结构。数组就是一张哈希表,哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素,如下图所示:哈希表一般用来快速判断一个元素是否出现集合里。哈希函数哈希函数通过特定编码方式,可以将其......
  • 发现一个超级赞的网站,每日更新热门AI产品
    发现了一个超级无敌赞的网站!可以看到每日热门产品榜单,大致一翻,看到好几个好玩的项目~简单介绍ProductHunt每日热榜是一个基于GitHubAction的自动化工具,它能够每天定时生成ProductHunt上的热门产品榜单Markdown文件,并自动提交到GitHub仓库中。该项目旨在帮助用户......
  • 图:207课程表 题解:入度数组,邻接表,队列,拓扑排序
    207.课程表-力扣(LeetCode)没做出来,参考题解,这篇题解写的非常好。把一个有向无环图转成线性的排序就叫 拓扑排序。(没太懂这句话的意思)classSolution{public:boolcanFinish(intnumCourses,vector<vector<int>>&prerequisites){vector<int>inDegre......
  • 【题解】【数组】—— [NOIP2005 普及组] 校门外的树
    【题解】【数组】——[NOIP2005普及组]校门外的树[NOIP2005普及组]校门外的树题目描述输入格式输出格式输入输出样例输入#1输出#1提示1.题意解析2.AC代码[NOIP2005普及组]校门外的树通往洛谷的传送门题目描述某校大门外长度为......
  • 「数组」堆排序 / 大根堆优化(C++)
    目录概述核心概念:堆堆结构数组存堆思路算法过程up()down()Code优化方案大根堆优化Code(pro)复杂度总结概述在「数组」快速排序/随机值优化|小区间插入优化(C++)中,我们介绍了三种基本排序中的冒泡排序与分治思想结合的算法:快速排序。本文我们来讲第二种基本排......
  • 1张超级“支付清算架构”图
    在支付行业的快速发展中,理解和掌握支付清算架构对于从业人员来说至关重要。本文将通过一张精心绘制的“超级支付清算架构图”,带领读者深入探索支付生态的全貌。这张图不仅包含了丰富的支付组织、系统建设和账户基础等信息,而且通过高维度抽象,展示了它们之间复杂的交互关系。本......
  • 数组的使用
    1.基本使用——for循环1.数组的打印2.数组的总和计算3.数组的最大值选取2.进阶使用1.foreach循环(增强for循环)2.使用方法输出数组(将数组输入进形参)3.反转数组定义一个新的数组,让其容量与前面的数组一致,再通过for循环,将新的数组的每一次循环都与原来数组循环相反,从而......
  • 【算法】【线性表】【数组】买卖股票的最佳时机
    1 题目给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你......