树状数组

树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。

树状数组和线段树很像,但能用树状数组解决的问题,基本上都能用线段树解决,而线段树能解决的树状数组不一定能解决。相比较而言,树状数组效率要高很多。

C1 = A1

C2 = A1 + A2

C3 = A3

C4 = A1 + A2 + A3 + A4

C5 = A5

C6 = A5 + A6

C7 = A7

C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

...

C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16

通过二进制,将数组的节点序号都转化成二进制。

就是这样的:

1--->001     C1 = A1

2--->010     C2 = A1 + A2

3--->011     C3 = A3

4--->100     C4 = A1 + A2 + A3 + A4

5--->101     C5 = A5

6--->110     C6 = A5 + A6

7--->111     C7 = A7

8--->1000   C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

但是这又有什么关系呢?

这里有一个有趣的性质:

设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,

所以很明显:Cn = A(n – 2^k + 1) + A(n-2^k+2)+... + An

什么意思呢?举个栗子,1对应的二进制是001,二进制末尾0的个数为0,所以k=0,所以C1=A(1-2^k+1)+...An 就是C1=A(1-2^0+1)=A(1);

再来个栗子,4对应的二进制是100,二进制末尾0的个数为2,所以k=2,所以C4=A(4-2^2+1)+A(4-2^2+2)+...+A(4)=A(1)+A(2)+A(3)+A(4);

再搞不懂就自己再手推几个数试试就可以了。

至于怎么得出来的这个神奇的东西,就是靠二进制。

接下来就是怎么代码实现这个呢?

就是要靠神奇的lowbit了。

int lowbit(int x)
{
return x&(-x);
}

x&(-x)就是整数x与其相反数(负号取反)的按位与:相同位的两个数字都为1,则为1;若有一个不为1,则为0,即:1&1=1,0&1=0,0&0=0;

计算机中负数使用对应正数的补码来表示。

-x就是x对应的二进制数先各位取反,0变成1,1变成0。然后最低位加1。

举个栗子,4对应二进制为100;-4对应的为011+1=100,所以为(100)&(100)所以为100。

知道这个就可以进行区间查询啦。

区间查询利用C[i]求A数组前i个的和;

//代码1:
int SUM(int n)
{
int s=;
while(n>){
s+=c[n];
n-=lowbit(n);
}
return s;
} //代码2:
int SUM(int n)
{
int s=;
for(int i=n;i>;i-=lowbit(i))
s+=c[i];
return s;
}

两个代码哪个好理解就理解哪个。

接着刚刚举的栗子4,求A数组前4个数的和;

lowbit(4)得出100;然后100就是4,所以为s+=c[4];此时i=4,4-lowbit(4)=100-100=0;结束。

再举个栗子7,求前7个数的和,就是s+=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7];

因为

1--->001     C1 = A1

2--->010     C2 = A1 + A2

3--->011     C3 = A3

4--->100     C4 = A1 + A2 + A3 + A4

5--->101     C5 = A5

6--->110     C6 = A5 + A6

7--->111     C7 = A7

8--->1000  C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

所以为C[4]+C[6]+C[7];

就是C[100]+C[110]+C[111];

首先s+=c[7];

然后lowbit[7]=(111)&(001)=001;此时i=7,所以为7-lowbit(7)=111-001=110,110就是6;s+=c[6];

lowbit(6)=(110)&(010)=010;此时i=6,所以为6-lowbit(6)=110-010=100,100就是4;s+=c[4];

lowbit(4)=(100)&(100)=100;此时i=4,所以为4-lowbit(4)=100-100=0,结束。

所以得到A数组中前7个数的和为C[7]+C[6]+C[4];

不懂的话再自己手推一个数就差不多懂了。

接下来就是单点更新。

单点更新要从下往上依次更新。

//代码1:
void add(int x)
{
while(x<=N){
++a[x];
x+=lowbit(x);
}
} //代码2:
void add(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=y;
}

更新过程仔细想一想就是查询过程的逆过程;

举个栗子,更新A1,还要继续更新C[1],C[2],C[4],C[8];

就是C[001],C[010],C[100],C[1000];

i=1;C[1]+=A[1];

lowbit(1)=(001)&(001)=001;此时i=1,所以为1+lowbit(1)=001+001=010,010就是2;C[2]+=A[1];

lowbit(2)=(010)&(110)=010;此时i=2,所以为2+lowbit(2)=010+010=100,100就是4;C[4]+=A[1];

lowbit(4)=(100)&(100)=100;此时i=4,所以为4+lowbit(4)=100+100=1000,1000就是8;C[8]+=A[1];结束。

好了,理解了树状数组就开始贴代码了。(;´д`)ゞ

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541

题目大意:

输入n个星星坐标位置,某个星星的左下有 i 颗星星(x或y相等算数),则这个星星就是level i的,输出的内容有n行:level 0~n-1的星星个数。输入降低了难度,是按照“按Y从小到大,如果Y相同则X从小到大”的顺序输入的,这就是一维的树状数组了,因为后面坐标的出现根本不会影响前面计算完的个数。
 
解题思路:每次输入一个坐标就查询它的左下角有i个星星,然后ans[i]++,再将这个点加入到树中即可。
附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 32005
int n,x,y,c[maxn],ans[maxn]; int lowbit(int x){return x&(-x);}
int sum(int n)
{
int sum=;
for(int i=n;i>;i-=lowbit(i))
sum+=c[i];
return sum;
}
void add(int x)
{
for(int i=x;i<=maxn;i+=lowbit(i))
c[i]++;
}
int main()
{
while(~scanf("%d",&n))
{
memset(ans,,sizeof(ans));
memset(c,,sizeof(c));
for(int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
ans[sum(x+)]++; //坐标中有(0,0),但树状数组中没有0,故整体坐标加1
add(x+);
}
for(int i=;i<n;i++)
printf("%d\n",ans[i]);
}
return ;
}

树状数组入门 hdu1541 Stars的更多相关文章

  1. POJ 2352 stars (树状数组入门经典!!!)

    Stars Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 54352   Accepted: 23386 Descripti ...

  2. poj2299树状数组入门,求逆序对

    今天入门了树状数组 习题链接 https://blog.csdn.net/liuqiyao_01/article/details/26963913 离散化数据:用一个数组来记录每个值在数列中的排名,不 ...

  3. 树状数组 || POJ 2352 Stars

    Astronomers often examine star maps where stars are represented by points on a plane and each star h ...

  4. [树状数组]数星星 Stars

    数 星 星 S t a r s 数星星 Stars 数星星Stars 题目描述 天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标.如果一个星星的左下方(包含正左和正下)有 k k k 颗星星 ...

  5. POJ 2299 Ultra-QuickSort 求逆序数 (归并或者数状数组)此题为树状数组入门题!!!

    Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 70674   Accepted: 26538 ...

  6. Binary Indexted Tree 树状数组入门

    感谢http://www.cnblogs.com/xudong-bupt/p/3484080.html 树状数组(BIT)是能够完成下述操作的数据结构: 给定一初始值全为零的数列a1,a2a,a3.. ...

  7. st表树状数组入门题单

    预备知识 st表(Sparse Table) 主要用来解决区间最值问题(RMQ)以及维护区间的各种性质(比如维护一段区间的最大公约数). 树状数组 单点更新 数组前缀和的查询 拓展:原数组是差分数组时 ...

  8. HDU 1541 树状数组

    树状数组入门博客推荐 http://blog.csdn.net/qq_34374664/article/details/52787481 Stars Time Limit: 2000/1000 MS ...

  9. HDU1556(树状数组)

    Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

随机推荐

  1. [转帖] SS, SP, BP 三个寄存器

    SS, SP, BP 三个寄存器 https://blog.csdn.net/vspiders/article/details/55669265 这么看 计算机组成原理 还有 考试的很多题目非常有用啊 ...

  2. 【转帖】Linux的历史----Linux内核剖析(一)

    Linux的历史----Linux内核剖析(一) 2015年04月09日 10:51:09 JeanCheng 阅读数:11351更多 所属专栏: Linux内核剖析    版权声明:本文为博主原创文 ...

  3. .Net的EF+MVC框架使用T4生成各个层的代码的,在新增表的时候,调不到新增的实体

    如果确认有这个实体的话,只需要把T4模板全部重新生成就可以了

  4. Oracle 中sql文件的导入导出

    导出 一般导入的时候我用的是命令行 imp c##zs/@orcl fromuser=c##zs touser=c##zs file=D:\java\.dmp ignore=y c##zs 是创建的用 ...

  5. Window上安装—Docker 笔记

    本文转自:http://cnodejs.org/topic/55a24267419f1e8a23a64367 需求 想玩nodeClub 源码跑起来,结果window 上各种报错,各种依赖软件要装的感 ...

  6. linux上如何让other用户访问没有other权限的目录

    目前遇到一个问题,一个other用户要访问一个目录,他需要在这个目录下创建文件,因此这个目录需要一个写权限,于是就给了这个目录777的权限,这样这个权限有点太大了,很容易出现安全问题,那我们应该怎么办 ...

  7. layui loading

    layer.msg('加载中', { icon: 16 ,shade: 0.4}); layer.load(2);风格二 setTimeout(function(){ layer.closeAll(' ...

  8. LodopJS代码模版的加载和赋值

    Lodop模版有两种方法,一种是传统的JS语句,可以用JS方法里的eval来执行,一种是文档式模版,是特殊格式的base64码,此篇博文介绍JS模版的加载和赋值.两种模版都可以存入一下地方进行调用,比 ...

  9. M - 约会安排 HDU - 4553 线段树 (最长连续段)

    中文题面 思路:维和两个区间  一个是女神区间 一个是基友区间  如果是基友要预约时间 直接在基友区间查询可满足的起点 (这里先判tree[1].m >=length也就是有没有这样的区间满足时 ...

  10. Server socket

    用法都一样 区别:  self.request   TCP  self.requsst 代表具体的链接 UDP  self.requst 代表一个小元组(元组里面: 第一个元素 客户端发来的数据 ,第 ...