[笔记]: 树状数组
来源:互联网 发布:tfboys三只的关系知乎 编辑:程序博客网 时间:2024/06/14 12:03
主要看图
i往上找就是i+=2^k; 往下就是减 k是i的二进制右边0的个数
2^k 直接等于i&(-i);
传送门:写的很好
总结
首先,明白树状数组所白了是按照二分对数组进行分组;维护和查询都是O(lgn)的复杂度,复杂度取决于最坏的情况,也是O(lgn);lowbit这里只是一个技巧,关键在于明白c数组的构成规律;分析的过程二进制一定要深入人心,当作心目中的十进制。
/*树状数组定义一个a数组一个c数组 记录和c[i]=a[i-2^k+1]+...a[i] k位i的二进制右边0的个数计算的时候计算a[1]+..a[r]-(a[1]+...a[l])的和 即为从l开始到r的和 用处有两个:1.区间查询2.单点更新样例输入:51 2 3 4 5 (数组元素) 2 4 (左区间和右区间) 输出:9 (左右区间元素和) */#include<iostream>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<cstdio>using namespace std;int a[1000],c[1000];int n;int lowbit(int i){ return i&(-i);}//这样就可以直接算出2^k(k是2进制i中右边0的个数)void change(int i,int x){ while(i<=n)//一直往上走 如 样例1->2->4->8 5->6->8 { c[i]+=x; i+=lowbit(i); }}int getsum(int x){ int sum=0; while(x>0){ sum+=c[x]; x-=lowbit(x); } return sum;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); change(i,a[i]); } int l;int r; scanf("%d%d",&l,&r); //cout<<getsum(r)<<endl; //cout<<getsum(l-1)<<endl; cout<<getsum(r)-getsum(l-1)<<endl; return 0;}
更新元素计算
/*树状数组 更新元素再求和 (更新数组中的元素 求左右区间内的元素和) 样例输入:51 2 3 4 5 (数组元素) 2 4 (左区间和右区间) 1 (更新一组) 2 5(把二换成5) 输出:12 (左右区间元素和) */#include<iostream>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<cstdio>using namespace std;int a[1000],c[1000];//一个a数组 一个c数组 int n;int lowbit(int i){ return i&(-i);}//这样就可以直接算出2^k(k是2进制i中右边0的个数)void change(int i,int x){ while(i<=n) { c[i]+=x; i+=lowbit(i); }}void deal(int i,int x){ int k=x-a[i];//差值 while(i<=n){ c[i]+=k; i+=lowbit(i); }}int getsum(int x){ int sum=0; while(x>0){ sum+=c[x]; x-=lowbit(x); } return sum;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]);//一边读入一遍更新c数组 change(i,a[i]); } int l;int r; scanf("%d%d",&l,&r); int m; scanf("%d",&m);//更新元素的组数 for(int i=1;i<=m;i++){ int p,q;//更新元素的位置和更新后的值 scanf("%d%d",&p,&q); deal(p,q); } //cout<<getsum(r)<<endl; //cout<<getsum(l-1)<<endl; cout<<getsum(r)-getsum(l-1)<<endl; return 0;}
树状数组求逆序对
可见此网页
/*样例51 5 2 4 3 输出 4 */#include<iostream>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<cstdio>using namespace std;int c[100010];struct node{ int v,p;}a[100010];int n;int lowbit(int i){ return i&(-i);}void update(int i){ while(i<=n)//一直往上走 如 样例1->2->4->8 5->6->8 { c[i]++; i+=lowbit(i); }}int getsum(int x){ int sum=0; while(x>0){ sum+=c[x]; x-=lowbit(x); } return sum;}bool cmp(node xx,node yy){ return xx.v<yy.v;}int main(){ scanf("%d",&n); int ans=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i].v); a[i].p=i; } sort(a+1,a+1+n,cmp);//排序:离散化 如果a[i].v是10000000 那么c的内存就要到1000000 但是排序以后再找逆序对在内存和时间上更优 for(int i=1;i<=n;i++){ update(a[i].p); ans+=i-getsum(a[i].p); //cout<<i<<"-"<<getsum(a[i].p)<<"="<<ans<<endl; } cout<<ans; return 0;}
阅读全文
0 0
- [笔记] 树状数组
- 树状数组学习笔记
- 树状数组学习笔记
- 学习笔记----树状数组
- 树状数组学习笔记
- 树状数组拓展笔记
- 【数据结构】树状数组笔记
- 学习笔记:树状数组
- 树状数组学习笔记
- [笔记]: 树状数组
- 【数据结构】树状数组笔记
- [树状数组] 笔记
- [笔记]浅谈树状数组
- 树状数组入门笔记
- 树状数组学习笔记
- 树状数组学习笔记+poj2029
- 学习笔记 BIT(树状数组)
- 【学习笔记】树状数组求逆序对
- (一)Kafka中文教程-初识kafka
- Shader的介绍
- 【解决】linux下svn权限配置不起作用
- java基础提高篇--类型转换
- LeetCode 82. Remove Duplicates from Sorted List II pre指针,首元素的处理
- [笔记]: 树状数组
- [iOS] objc_setAssociatedObject objc_getAssociatedObject 简单明了的一个理解
- JVM加载class文件的原理机制
- 《Android源码设计模式解析与实战》读书笔记(十五)——模板方法模式
- Java类加载器介绍总结
- 实际项目中常用的加密算法及使用场景
- jsp页面的中循环获取数据
- Linux 删除文件夹和文件的命令(强制删除包括非空文件)
- javascript闭包