zoukankan
html css js c++ java
树状数组
/* TreeArray.h 树状数组,一维和二维都有。数组必须从1开始 问题: 已知数组a[],元素个数为n,现在更改a中的元素,要求得新的a数组中i到j区间内的和 解决方法: 从图中不难发现,c[k]存储的实际上是从k开始向前数k的二进制表示中右边第一个1所代表的数字 个元素的和(这么说可能有点拗口,令lowbit为k的二进制表示中右边第一个1所代表的数字,然后 c[k]里存的就是从a[k]开始向前数lowbit个元素之和) 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 这么存的好处: 无论是树状数组还是线段树,都用到了分块的思想 方便计算,我们可以用位运算轻松地算出lowbit. 时间复杂度: 对于更改元素来说,如果第i个元素被修改了,可以直接在c数组里面进行相应的更改,如图中的例子, 假设更改的元素是a[2],那么它影响到得c数组中的元素只有c[2],c[4],c[8],我们只需一层一层往 上修改就可以了,这个过程的最坏的复杂度也不过O(logN); 对于查找来说,如查找s[k],只需查找k的二进制表示中1的个数次就能得到最终结果,比如查找s[7],7的二进制表示中有3个1,也就是要查 找3次,到底是不是呢,我们来看上图,s[7]=c[7]+c[6]+c[4] 怎么实现这个过程: 还以7为例,二进制为0111,右边第一个1出现在第0位上,也就是说要从a[7]开始向前数1个元素(只 有a[7]),即c[7]; 然后将这个1舍掉,得到6,二进制表示为0110,右边第一个1出现在第1位上,也就是说要从a[6]开始 向前数2个元素(a[6],a[5]),即c[6]; 然后舍掉用过的1,得到4,二进制表示为0100,右边第一个1出现在第2位上,也就是说要从a[4]开始 向前数4个元素(a[4],a[3],a[2],a[1]),即c[4]. */ #include<iostream> using namespace std; #define MAX 1002 class TreeArray { public: int **s; int type; public: TreeArray(int t); ~TreeArray(); void clear(); int lowbit(int x){return x&(-x);}; void modify(int x, int value); void modify(int x, int y, int value); int sum(int x); int sum(int x, int y); }; TreeArray::TreeArray(int t):type(t) { int i; s = new int*[MAX+1]; //一维 if(type == 1) { for(i = 0; i <= MAX; i++) s[i] = new int; } //二维 else if(type == 2) { for(i = 0; i <= MAX; i++) s[i] = new int[MAX+1]; } } TreeArray::~TreeArray() { int i; for(i = 0; i <= MAX; i++) delete []s[i]; delete []s; } void TreeArray::clear() { int i, j; for(i = 0; i <= MAX; i++) { if(type == 1) s[i][0] = 0; else { for(j = 0; j <= MAX; j++) s[i][j] = 0; } } } void TreeArray::modify(int x, int value) { while(x <= MAX) { s[x][0] += value; x += lowbit(x); } } void TreeArray::modify(int x,int y,int value) { int temp = y; while(x <= MAX) { y = temp; while(y <= MAX) { s[x][y] += value; y = y + lowbit(y); } x = x + lowbit(x); } } int TreeArray::sum(int x) { int ans=0; while(x > 0) { ans += s[x][0]; x -= lowbit(x); } return ans; } int TreeArray::sum(int x,int y) { int ans=0, temp = y; while(x > 0) { y = temp; while(y > 0) { ans += s[x][y]; y = y - lowbit(y); } x = x - lowbit(x); } return ans; }
查看全文
相关阅读:
C#.NET常见问题(FAQ)-如何在不同窗体之间传递值
C#.NET常见问题(FAQ)-如何不显示窗口的关闭按钮
C#.NET常见问题(FAQ)-如何判断两个类是否相同类型
C#.NET常见问题(FAQ)-如何判断某个字符是否为汉字
C#.NET常见问题(FAQ)-如何改变字符串编码
C# 多线程编程 ThreadStart ParameterizedThreadStart
C# 线程调用主线程中的控件
LINQ to XML 编程基础
LINQ to XML 建立,读取,增,删,改
WinForm 自动完成控件实例代码简析
原文地址:https://www.cnblogs.com/windmissing/p/2559890.html
最新文章
转桌面端开发的感受
3月份周度分享(三)
3月份周度分享(二)
3月份周度分享(一)
初学者摸索之算法学习
开工第一周
了解一下还是有益的
Unable to parse composition
Android 常用炫酷控件(开源项目)git地址汇总
GitHub 上受欢迎的 Android UI Library整理
热门文章
AndroidManifest.xml 详解
Mysql外键约束之CASCADE、SET NULL、RESTRICT、NO ACTION
mysql 计算两点经纬度之间的直线距离(具体sql语句)
vertx 异步编程指南 step7-保护和控制访问
vertx 异步编程指南 step8-使用RxJava进行反应式编程
《Netty 权威指南(第2 版)》目录
百科知识 买房子的满五唯一和满二唯一什么意思
如何博客搬家,从博客园搬家到CSDN
C#.NET常见问题(FAQ)-控制台程序如何做弹窗
WinRAR如何批量分别压缩不同的文件夹
Copyright © 2011-2022 走看看