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) [树状数组]的更多相关文章

  1. HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)

    Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Tota ...

  2. 计蒜客 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 ...

  3. bzoj1901--树状数组套主席树

    树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...

  4. BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

    [题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...

  5. POJ 2299 Ultra-QuickSort 逆序数 树状数组 归并排序 线段树

    题目链接:http://poj.org/problem?id=2299 求逆序数的经典题,求逆序数可用树状数组,归并排序,线段树求解,本文给出树状数组,归并排序,线段树的解法. 归并排序: #incl ...

  6. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

  7. BZOJ1901 - Dynamic Rankings(树状数组套主席树)

    题目大意 给定一个有N个数字的序列,然后又m个指令,指令种类只有两种,形式如下: Q l r k 要求你查询区间[l,r]第k小的数是哪个 C i t  要求你把第i个数修改为t 题解 动态的区间第k ...

  8. bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Stat ...

  9. [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

    题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...

随机推荐

  1. cpp(第五章)

    1.副作用,指的是在计算表达式时对某些东西(如存储在变量的值)进行修改:顺序点,是程序执行过程中的一个点,在这里,进入下一步之前将确保对所有的副作用 都进行评估.(分号就是一个顺序点).for exa ...

  2. JavaBean自动生成get和set方法

    用Myeclipse开发java web程序,写javabean的时候,如果字段很多的话,写get和set方法是一件很无语和浪费时间的事情,所以Myeclipse提供了一个自动生成这些方法的功能.   ...

  3. Azure 认知服务 (2) 计算机视觉API - 分析图像

    <Windows Azure Platform 系列文章目录> 在上一节内容中,笔者介绍了微软认知服务的概览. 在本节中,笔者将详细介绍微软认知服务中的一种:计算机视觉 (Computer ...

  4. colinux

    Colinux是什么?2004年,由一名21岁的以色列学生与几名日本的自由程序员合作开发出了一个名为“Cooperative Linux”即“CoLinux”的Linux程序,该程 序可使Linux的 ...

  5. 对象的序列化与反序列化-serialize与unserialize

    1. 简介 对象的序列化的基本概念: 所谓对象的序列化,就是可以把某个对象的属性名称,属性值, 属性类型,类名 以字符串的形式保存到文件中,在你需要的时候可以重新恢复. 对象的反序列化的基本概念, 是 ...

  6. 使用ConfuserEx加密混淆程序以及如何脱壳反编译

    一,准备如下工具: ConfuserEx.UnConfuserEx.Fixer.ConfuserExStringDecryptor.ConfuserExSwitchKiller.de4dot.ILSp ...

  7. MySql三大范式与数据库设计和表创建常用语句

    [数据库设计的三大范式] 1.第一范式(1NF First Normal Fromate):数据表中的每一列(字段),必须是不可拆分的最小单元.也就是确保每一列的原子性. 例如: userInfo: ...

  8. (cljs/run-at (JSVM. :browser) "搭建刚好可用的开发环境!")

    前言  书接上一回,在了解cljs基本语法后并在clojurescript.net的奇特错误提示后,我们必须痛定思痛地搭建一个本地的开发环境,以便后续深入地学习cljs. 现有的构建工具  由于浏览器 ...

  9. 《JavaScript高级程序设计》笔记一

    第一章 JavaScript简介 一.JavaScript的起源 JavaScript诞生于1995年.当时,它的主要作用是处理一些输入验证操作.之前的话,都是把表单数据发送到服务器端,然后再去判断有 ...

  10. mysql 转义字符

    在用户提交表单的时候,有的用户会提交一些特殊字符,比如单引号双引号,此时,如果直接按正常字符串插入数据库的话,可能会出现无法正确插入数据库 PDO::quote 转义mysql语句中的单引号和双引号 ...