树状数组(瞎bb) [树状数组]
Copyright:http://www.cnblogs.com/ZYBGMZL/
树状数组是一个利用一维数组和位运算组成的求解区间问题的高效数据结构,其构造如图所示

首先,我们要用它解决单点修改、区间查询的操作。
根据这张图我们建立一个数组bit[],下标就是图中显示的十进制数。bit[i]就表示了图中所示的一段区间的和,例如bit[6]=sum(5,6),bit[4]=sum(1,4)。
下标最大值为序列的长度n。
我们接下来要求一段序列中left到right的和,就可以转化为求sum(1,right)-sum(1,left)。
那么对于已知的x,怎么求sum(1,x)呢?

在这样一个栗子(上图)中,我们需要求得sum(1,6)的值,可以将其转化为求bit[6]+bit[4]。
显而易见,只要将6的二进制数0110的最低位1删去,就得到0100,对应了10进制的4。

再举一个栗子(如上图),我们想求sum(1,3)的值,只要求bit[2]+bit[3]就好了。
变化规律和上一个一样。(0011---->0010)

对于多段区间,也满足一样的规律(上图)。
我们总结,对于x,只要不断减去x中最低位的1,将得到的bit[x]相加就可以得到结果了。
用这样一个方法获取x的最低位1
x&-x
就得到了这样一个操作代码
int sum(int x){
int sum=;
while(x){
x+=bit[x];
x-=x&-x;
}
return sum;
}
查询的问题解决了,接下来要处理修改的操作了。

举个栗子,假如对3点进行加a的操作,在bit[3]修改的同时,bit[4]和bit[8]也要相应修改。
观察这3个数(3,4,8)的二进制数,可以发现,只要不断地加上其最低位的1,就可以完成操作了。
0011+0001=0100
0100+0100=1000
再对所得的数判断是否大于n即可。
于是我们得到了这样一个单点修改的操作代码。
void add(int x,int a){
while(x<=n){
bit[x]+=a;
x+=x&-x;
}
}
以上是树状数组操作最简单的模型,除此之外,树状数组还有区间修改、单点查询,以及区间修改、区间查询的功能。
区间修改、单点查询
//改段求点型操作 //b[i]表示区间1...i一共变化的量
int b[];
//原始数组
int a[]; void ADD(int x, int c)
{
for (int i=x; i>; i-=i&(-i))
b[i] += c;
} void add(int left,int right,int c){
if(left-1) ADD(left-,-c);
ADD(right,c);
} int SUM(int x)
{
int s = ;
for (int i=x; i<=n; i+=i&(-i))
s += b[i];
return s+a[x];
}
区间修改、区间查询
//改段求段型:
//这是最复杂的模型,需要两个辅助数组:B[i]表示a[1..i]到目前为止共被整体加了多少(和模型2中的一样)
//C[i]表示a[1..i]到目前为止共被整体加了多少的总和(或者说,C[i]=B[i]*i)。 //对于ADD(x, c),只要将B[x]加上c,同时C[x]加上c*x即可(根据C[x]和B[x]间的关系可得); //而ADD(x, c)操作是这样影响a[1..i]的和的:若x小于i,则会将a[1..i]的和加上x*c,
//否则(x>=i)会将a[1..i]的和加上i*c。也就是,a[1..i]之和 = B[i..N]之和 * i + C[1..i-1]之和。
//这样对于B和C两个数组而言就变成了“改点求段”(不过B是求后缀和而C是求前缀和)。
//另外,该模型中需要特别注意越界问题,即x=0时不能执行SUM_B操作和ADD_C操作。 //【1】修改操作:将A[l..r]之间的全部元素值加上c;
//ADD_B(r, c); ADD_C(r, c);
//if (l > 1) {ADD_B(l - 1, -c); ADD_C(l - 1, -c);}
//【2】求和操作:求此时A[l..r]的和。
//SUM(r) - SUM(l - 1)。 //B[i]表示区间1...i变化量
int B[];
//C[i]表示区间1...i变化量的总和,有c[i]=b[i]*i
int C[]; void ADD_B(int x, int c)
{
for (int i=x; i>; i-=i&(-i)) B[i] += c;
} void ADD_C(int x, int c)
{
for (int i=x; i<=n; i+=i&(-i)) C[i] += x * c;
} int SUM_B(int x)
{
int s = ;
for (int i=x; i<=n; i+=i&(-i)) s += B[i];
return s;
} int SUM_C(int x)
{
int s = ;
for (int i=x; i>; i-=i&(-i)) s += C[i];
return s;
} int SUM(int x)
{
if (x) return SUM_B(x) * x + SUM_C(x - ); else return ;
}
树状数组(瞎bb) [树状数组]的更多相关文章
- HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
Weak Pair Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Tota ...
- 计蒜客 1460.Ryuji doesn't want to study-树状数组 or 线段树 (ACM-ICPC 2018 徐州赛区网络预赛 H)
H.Ryuji doesn't want to study 27.34% 1000ms 262144K Ryuji is not a good student, and he doesn't wa ...
- bzoj1901--树状数组套主席树
树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...
- BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树
[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...
- POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树
题目链接:http://poj.org/problem?id=2299 求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法. 归并排序: #incl ...
- BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树
[题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...
- BZOJ1901 - Dynamic Rankings(树状数组套主席树)
题目大意 给定一个有N个数字的序列,然后又m个指令,指令种类只有两种,形式如下: Q l r k 要求你查询区间[l,r]第k小的数是哪个 C i t 要求你把第i个数修改为t 题解 动态的区间第k ...
- bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1384 Solved: 629[Submit][Stat ...
- [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】
题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...
随机推荐
- 本地修改js代码并时时生效的解决办法
js作为客户端语言(当然它也可以作服务端语言),非常强悍,一般情况下,我们都是在开发阶段不停的改,然后上线之后就作为稳定运行的代码. 然而有时候可能因为js写得有问题,导致上线后,某些功能无法使用,这 ...
- 使用java实现发送邮件的功能
首先要在maven添加javamail支持 <dependency> <groupId>javax.activation</groupId> <artifac ...
- SQL Server Alwayson读写分离配置
标签:MSSQL/只读路由 概述 Alwayson相对于数据库镜像最大的优势就是可读副本,带来可读副本的同时还添加了一个新的功能就是配置只读路由实现读写分离:当然这里的读写分离稍微夸张了一点,只能称之 ...
- Bash内置命令exec和重定向
Bash内置命令exec可以替换当前程序而不需要启动一个新的进程,可以改变标准输入和输出而不需要启动一个新的子进程.如果文件用exec打开,read命令就会把文件指针每次指向下一行直到文件的末尾,如果 ...
- 浅谈MVC Form认证
简单的谈一下MVC的Form认证. 在做MVC项目时,用户登录认证需要选用Form认证时,我们该怎么做呢?下面我们来简单给大家说一下. 首先说一下步骤 1.用户登录时,如果校验用户名密码通过后,需要调 ...
- LoadRunner11_录制Oracle数据库脚本
[oracle环境] ①oracle:无需在本地安装oracle,但是oracle的odbc驱动一定要装:(我的安装路径为 D:\oracle ).安装好后在环境变量 " Path &quo ...
- 一步一步教你将开源项目上传到jcenter
最近闲着看了一下jcenter的使用,也想将自己使用频率比较高的东西抽成类库,然后通过compile来使用,提高开发效率,本来以为挺简单的,但是网上介绍的比较模糊,很多博客也比较老了,不适用,花了我一 ...
- JS面向对象一
面向对象分为三大类 封装,继承,多态! 封装就是在一个函数方法中嵌套另外一个函数方法,外层函数方法返回内层函数方法里面的结果,其中内层函数要调用外层函数定义的局部变量 每个函数方法就是一个局部作用域, ...
- php追加数组
<?php //追加数组 array_merge_recursive()函数与array_merge()相同,可以将两个或多个数组合并在一起,形成一个联合的数组.两者之间的区别在于,当某个输入数 ...
- jQuery星级评分插件
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="Con ...