早就想着把以前搞acm的算法复习一遍,那可是瑰宝啊,一直没时间,之前面实习就有此感慨,以前学的算法都忘了,明日要去面个不知名的公司,准备下吧,先把树状数组和TRIE图复习下,明天凑合应对。
不多说,上问题:
给你一个数组a[N],假设存int数,对这个数组的操作有2种:(1)修改数组中某元素的值(2)查询该数组任意区间的和。见poj2481.
最朴素想法:在原数组上操作,对于每个操作(1),修改该位置的值,对于(2)操作,遍历数组求和,复杂度为M+Q*N(M为修改次数,Q为查询次数,N为数组size),当N很大时无法忍受。
树状数组解决此问题的复杂度为:(M+Q)*log2(N);
原理:查询某区间[a,b]的和等价于求解sum(b)-sum(a-1)(sum(k)为[1,k]的和);故转化为求解前k项和的问题了。联想线段树分段处理的思想,此处不是二分,而是另一种分段方法。其实可用线段树解决之,但没有树状数组处理简单。开另一数组C[N],元素C[k]存储的值为区间[k-lowbit(k]+1,k]的和。lowbit(k)=k表示成二进制后最右边的位代表的十进制数,即k能整除的最大的(2^x);举个例子:6,表示成2进制为00000110,最右边的位为第2位,故lowbit=2^(2-1)=2,6能整除的2的次方为2。上经典图:
C数组构成一个树状关系:C[x]分布在 log2(lowbit(x)) 层;每个C[k]只有一个父亲节点,子节点与其父节点之间的距离为lowbit(k)。
对于操作(1),修改某位置k的值,则对于数组C要修改包括a[k]的位置,k与下一个相关节点的距离为lowbit(k)。
对于操作(2),查询某位置k的sum(k),则一次查询包括k到1的sum的位置,k与其下一个相关节点的距离为lowbit(k)。
由图可知修改和查询的复杂度都为log2(N);
求lowbit很巧妙:x&(x^(x-1));
x:
x-1:
x^(x-1):
x&(x^(x-1))
看了下另外一个自己写的源码:原来还有一种更简单的lowbit求法:lowbit = x&(-x);
x:
~x:
-x=~x+1:
x&(-x)
类似巧妙的还有:判断一个数是否为2的次方if((x&-x)==x);
代码如下:
int lowbit(int x)//位运算求lowbit(x)
{
}
void add(int x,int val)//修改位置x的值,val为变化值,可为+-;
{
}
int getsum(int x)//求sum(x)
{
}可升级为2维及多维:修改2维矩阵某个值,求区间[x1,y1]~[x2,y2]的和。类似,代码如下:int lowbit(int x)
{
}
void add(int x,int y,int det)
{
}
int getsum(int x,int y)
{
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tmac_0817/archive/2011/04/23/6347438.aspx