POJ 2352(顺路讲解一下树状数组)
来源:互联网 发布:怎么测试网络是否掉包 编辑:程序博客网 时间:2024/04/25 07:23
接触到的第一道树状数组的题,AC之后感觉对树状数组思想的理解明显清晰了很多,入门必备呀。
先来讲讲树状数组吧。
上个图
如果要求区间和,例如求a3->a8,我们先用数组c来记录下来各个区间的和,那么就可以直接c8-c2就可以得到a3->a8的区间和了。
c[n]数组的下标是用来记录数组a[1]->a[n]的区间和。
再想,我们如果要求s->t的和可以怎么求?
是不是可以用(1->t)减去(1->s-1)?
同理,树状数组也可以用这种方式求和。比如求a[2]的话就可以用c[2]-c[1]来得到a[2]。
关于c数组的记录方法,就不得不提到x&(-x)这个表达式。
x&(-x)是用来计算每次查询或者更新时候c数组的偏移量。
通常写成函数的形式。
int lowbit(int x){ return x & (-x);}
关于树状数组的求区间和,如果求区间[1,8],那么直接c[8]就好,但是如果要求区间[4,8]该怎么办?
那么可以用区间[1,8]的和减去区间[1,3]的和就得到了区间[4,8]的和。
那又如何求区间[1,3]呢?我们可以c[2]+c[3]就得到了区间[1,3]的和了。
下面是求区间[1,x]和的函数:
int sum(int x){ int s = 0; while (x > 0) { s += c[x]; x -= lowbit(x); } return s;}
以求区间[1,3]为例,首先x等于3代入方程,3 > 0,则s = c[3],然后执行x-=lowbit(x);
让我们进入lowbit函数,首先3的二进制原码为0000 0011,-3为3的补码,则-3的二进制码为1111 1101,进行&运算之后为1,所以x-=1,此时x为2。由于2>0,所以s此时等于c[3] + c[2]。执行x-=lowbit(x)之后x = 0。循环结束,此时s已经是区间[1,3]的和了。
我们再来看树状数组的更新函数:
int update(int x, int num){ while (x <= MAX) { c[x] += num; x += lowbit(x); }}
和线段树一样,树状数组也是需要对节点所影响到的所有节点进行更新,采取从根到顶的方式。也就是对每个影响到的节点都加上更改信息。
树状数组时间复杂度O(log n)
————————————————————————分割线——————————————————————————————
题意:有n个星星节点,存在星星节点左下角(包括正左和正下)的其他星星节点,则该星星节点比它左下角的星星节点大,level 0表示该星星节点没有比他还小的节点,level 1表示存在一个比该星星节点小的点。输出统计好的每个level等级存在多少星星节点。
解题思路:为什么要用树状数组呢,因为如果你用for循环统计的话,由于数据很大然后又有很多组数据需要统计,那么肯定是会超时的,所以此时需要一种高效的数据结构(感觉像一句废话TAT),树状数组类似于线段树,能够很高效的解决区间问题,将这道题提炼一下其实也就是一个统计区间和的问题,线段树写起来好麻烦的=。=于是乎用了树状数组。
直接上代码:
/*因为是按照y升序输入,所以后面输入对前面输入并无影响**前x与后x如果相同,那么肯定后x是包含前x的,因为是按照y升序**即前后x虽是在同一列,但后x肯定在前x上面,即包含前x**PS:树状数组下标从1开始*/#include <iostream>#include <cstdio>#include <cstring>using namespace std;int level[32001];int c[32001];int lowbit(int x){ return x & (-x);}int sum(int x){ int s = 0; while (x > 0) { s += c[x]; x -= lowbit(x); } return s;}int update(int x){ while (x <= 32001) { c[x]++; x += lowbit(x); }}int main(){ int n; int x, y; while(~scanf("%d", &n)) { int N = n; memset(level, 0, sizeof(level)); memset(c, 0, sizeof(c)); while (n--) { scanf("%d %d", &x, &y); level[sum(x+1)]++; update(x+1); } for (int i = 0; i <= N - 1; i++) printf("%d\n", level[i]); } return 0;}
- POJ 2352(顺路讲解一下树状数组)
- 树状数组 (poj 2352)
- poj 2352(树状数组)
- POJ 2352 树状数组
- poj 2352 树状数组
- POJ 2352 树状数组
- poj 2352(树状数组)
- POJ 2352 树状数组
- POJ 2352 (树状数组)
- poj 2352 树状数组
- poj 2352树状数组
- 【树状数组】poj 2352
- POJ 2352(树状数组)
- poj 2352 树状数组
- poj 2352 树状数组
- poj 2352 树状数组
- poj 2352 树状数组
- POJ 2352 树状数组
- 银行卡发卡行标识代码及卡号
- Android学习实践:6.应用主题和布局
- 点击事件中获取点击的坐标
- 对于普通异常的处理
- JAVA编程基础(二)
- POJ 2352(顺路讲解一下树状数组)
- Hibernate各种主键生成策略与配置详解
- mysql 基于时间点恢复
- HDU 5464 Clarke and problem(类01背包)
- 创建、修改和删除表
- ArrayList、LinkedList、Vector的区别
- android studio 快捷键(mac)
- Josephus问题分析与实现
- 不使用c++内置的sqrt,求平方根