树状数组
来源:互联网 发布:高新区网络问政平台 编辑:程序博客网 时间:2024/06/15 20:44
结合这两个博客看懂的:
点击打开链接
‘
关于树状数组的实现
数据结构 - 树状数组 ( Binary Indexed Tree,BIT,二分索引树 ),它只有两种基本操作,并且都是操作线性表的数据的:
节点的含义:
每个整数都能表示为一些2的幂次方的和,比如13,其二进制表示为1101,所以它能表示为:13 = 2^0 + 2^2 + 2^3 .类似的,累积频率可表示为其子集合之和。在本文的例子中,每个子集合包含一些连续的频率值,各子集合间交集为空。比如累积频率c[13]=f[1]+f[2]+…+f[13],可表示为三个子集合之和(数字3是随便举例的,下面的划分也是随便举例的),c[13]=s1+s2+s3,其中s1=f[1]+f[2]+…+f[4],s2=f[5]+f[6]+…+f[12],s3=f[13]。
idx记为BIT的索引,r记为idx的二进制表示中最右边的1后面0的个数,比如idx=1100(即十进制的12),那么r=2。tree[idx]记为f数组中,索引从(idx-2^r +1)到idx的所有数的和,包含f[idx-2^r +1]和f[idx]。即:tree[idx]=f[idx-2^r +1]+…+f[idx],见表1.1和1.2,你就会一目了然。我们也可称idx对索引(idx-2^r +1)到索引idx负责。(We also write that idx is responsible for indexes from (idx-2^r +1)to idx)
关于2的k次方的求解:这里介绍一种O(1)的方法计算2k的方法。
int lowbit(int x) { return x & -x; }
关于求和的sum函数:
想要求i-index的和值
tree数组是这么定义的:tree[idx] = f[idx-2^r +1] +…+ f[idx]. 上面的程序sum加上tree[idx]后,去掉idx最后的1,假设变为idx1,那么有idx1 = idx-2^r , sum接下来加上tree[idx1]= f[idx1-2^r1 +1] +…+ f[idx1] = f[idx1-2^r1 +1] +…+ f[idx-2^r ],我们可以看到tree[idx1]表达示的最右元素为f[idx-2^r ],这与tree[idx]表达式的最左元素f[idx-2^r +1]无缝地连接了起来。所以,只需要这样操作下去,即可求得f[1]+…+f[idx],即c[idx]的结果。
所以代码如下
int sum(int idx){ int res = 0; while(idx > 0) { res += tree[idx]; idx -= (idx & -idx); } return res;}
关于更新的add函数:
更新操作就是之前提到的add(i, 1) 和 add(i, -1),更加具体得,可以推广到add(i, v),表示的其实就是 f[i] = f[i] + v。但是我们不能在原数组f上操作,而是要像求和操作一样,在树状数组tree上进行操作。
void add(int idx,int val){ while(idx <= n) { tree[idx] +=val; idx += (idx & -idx); }}
最后奉上一个求逆序数的题目吧:
HDU(1394)
#include <iostream>#include<string>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;const int maxn=5000+5;const int inf=0x3f3f3f3f;int n;int s[maxn];int tree[maxn*2];int sum(int idx){ int res = 0; while(idx > 0) { res += tree[idx]; idx -= (idx & -idx); } return res;}void add(int idx,int val){ while(idx <= n) { tree[idx] +=val; idx += (idx & -idx); }}int main(){ while(cin>>n) { int ans=inf; int res=0; memset(tree,0,sizeof(tree)); for(int i=0;i<n;i++) { scanf("%d",&s[i]); res+=sum(n)-sum(s[i]+1); add(s[i]+1,1); } if(res<ans) ans=res; for(int i=n-1;i>=0;i--) { res=res+s[i]-(n-s[i]-1); if(res<ans) ans=res; } printf("%d\n",ans); } //cout << "Hello world!" << endl; return 0; return 0;}
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 测试Markdown
- MySQL_008_基础_索引[简介]
- zookeeper集群某台机器故障替换步骤
- 自定义链表集合,无实现任何接口,继承
- 战狼2很火,但闲余之时看了 上甘岭、高山下的花环
- 树状数组
- Java Socket编程
- Install TensorFlow
- 29、C#:C#去除字符串的最后一个字符
- git的分支管理策略
- Trie+拓扑排序——Luogu3065 [USACO12DEC]第一!First!
- ZOJ 3449 Doraemon's Number Game III (数论)
- Paper read weekly(one)
- JVM(2):JVM内存结构