树状数组简单入门
来源:互联网 发布:js将字符串转化成数字 编辑:程序博客网 时间:2024/05/22 10:29
树状数组简单入门
树状数组是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和。但是每次只能修改一个元素的值,不如线段树的应用范围广,但是写起来比线段树简单很多,空间复杂度也会低一点。可以用来解一些像求逆序数的题。
上面这张图就表示了树状数组与原数组的关系
c数组完整的保存了a的所有的信息,我们可以通过对c数组的操作来查询a数组的区间和还有修改a数组的单个元素的值。
c是怎么表示a的呢?
c[i] = a[i – 2^k + 1] + … + a[i],k为t在二进制下末尾0的个数
按照上面的规则c[i]也可以认为是由a[i]向前加和lowbit(i)个a数组值
lowbit(i)可以用下面的代码求出:
int lowbit(int i){ return i&(-i);}
获得了c数组后要怎么求区间和呢?
我们可以利用c数组求出1~n区间内的区间和求解方法如下:
int sum(int i){ int sum = 0; while(i>0) { sum += c[i]; i =i - lowbit(i); } return sum;}
先令待求区间和为0,之后在依次加上c[i],c[i-lowbit(i)],c[i-lowbit(i)-lowbit(i-lowbit(i))]….显然最多加log2(i)次,所以求和的复杂度为O(n)。
为了清楚表示这个过程,用一张表格模拟1~8的求和过程
对任意区间[x,y]区间和可以简单的由sum[y]-sum[x-1]求得。
如何更新点的值呢?
改变a[i],必须要将包含a[i]的所有c[x]的值都改变掉,如何获取包含a[i]的c[x]呢?
从图上可以发现对任意c[i]他的父亲节点为c[lowbit(i)+i],显然我们第一个要改的值就是c[i],改变c[i]后逐步向上修改
(以a[i]加一个值为例)代码如下:
void add(int i,int value){ while(i<=N) { c[i] += value; i = i+ lowbit(i); }}
解决了上面的三个问题就可以用树状数组解题啦
下面给一道树状数组的题:hdoj1166
敌兵布阵
Description
C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。
中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇报第3个营地到第10个营地共有多少人!”Tidy就要马上开始计算这一段的总人数并汇报。但敌兵营地的人数经常变动,而Derek每次询问的段都不一样,所以Tidy不得不每次都一个一个营地的去数,很快就精疲力尽了,Derek对Tidy的计算速度越来越不满:”你个死肥仔,算得这么慢,我炒你鱿鱼!”Tidy想:“你自己来算算看,这可真是一项累人的工作!我恨不得你炒我鱿鱼呢!”无奈之下,Tidy只好打电话向计算机专家Windbreaker求救,Windbreaker说:“死肥仔,叫你平时做多点acm题和看多点算法书,现在尝到苦果了吧!”Tidy说:”我知错了。。。”但Windbreaker已经挂掉电话了。Tidy很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?不过如果你的程序效率不够高的话,Tidy还是会受到Derek的责骂的.
Input
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令
Output
对第i组数据,首先输出“Case i:”和回车,
对于每个Query询问,输出一个整数并回车,表示询问的段中的总人数,这个数保持在int以内。
ac码
#include <iostream>#include<cstdio>#include<cstring>using namespace std;const int MAX = 50005;int N;int c[MAX];int lowbit(int i){ return i&(-i);}void add(int i,int value){ while(i<=N) { c[i] += value; i = i+ lowbit(i); }}int sum(int i){ int sum = 0; while(i>0) { sum += c[i]; i =i - lowbit(i); } return sum;}int main(){ int T; int Case = 0; scanf("%d",&T); while(T--) { printf("Case %d:\n",++Case); memset(c,0,sizeof(c)); cin >> N; for(int i = 1; i <= N; i++) { int d; scanf("%d",&d); add(i,d); } char command[15]; while(scanf("%s",command)&&command[0]!='E') { if(command[0] == 'Q') { int x,y; scanf("%d%d",&x,&y); printf("%d\n",sum(y)-sum(x-1)); } if(command[0] == 'A') { int i,value; scanf("%d%d",&i,&value); add(i,value); } if(command[0] == 'S') { int i,value; scanf("%d%d",&i,&value); add(i,-value); } } } return 0;}
- 树状数组简单入门
- HDU 2689 Sort it 简单树状数组入门
- 树状数组 入门
- poj2352树状数组入门
- 树状数组入门
- 树状数组入门
- 树状数组入门理解
- 树状数组知识入门
- 树状数组入门
- 树状数组入门
- 树状数组入门笔记
- 简单树状数组-poj2352
- 树状数组简单应用
- hdu4911 简单树状数组
- HDU2838-简单树状数组
- 树状数组简单总结
- poj2299 树状数组入门题
- HDU-1541(树状数组入门)
- [C++]关于数据永久化的思考(不使用数据库)
- win10 完美屏蔽Flash右键菜单,内存播放Flash swf 文件(VC、 VB)f_in_box4.4 最新破解版
- 允许ubuntu下mysql远程连接
- c++中头文件iomanip
- 信长之野望14创造
- 树状数组简单入门
- Octave 线性代数 矩阵 2
- C#中多路广播与委托合并
- {题解}[jzoj3396] 【NOIP2013模拟】Rainbow的信号
- 【NOIP2013模拟】Rainbow的信号
- Python Numpy.ndarray ValueError:assignment destination is read-only
- sdut 2878 Circle 高斯消元
- OC 习题:股票K线计算
- NOIp2015 跳石头