[Pku 2352 2155 Hdu 3584] 线段树(五) {树状数组}
{
就我学过的数据结构而言
最优美的数据结构是并查集
然后是树状数组
再次是散列表
......
}
优美的含义就是简明 精巧
当然特别强大的数据结构一般都不好写
比如Splay 线段树 平衡树之类
所以也不是很优美
线段树确实强大 但是在有些情况下
我们可以用树状数组实现线段树的一部分功能
通常意义上的树状数组是一个一维数组 我们一般用c[]来记录
相对的 还有一个原数组a[] 记录原有的序列 c[]是基于a[]而产生的
树状数组可以实现查询区间和和修改单值的操作
这些操作线段树也可以实现 理论复杂度同样为O(Log2N)
但是树状数组的常数和编程复杂度更低
对于可以转化为这两个操作的问题 我们优先考虑树状数组
而且树状数组还有比线段树更好的可扩展性 可以轻易地扩展到高维
只需把通常意义上的树状数组改造成N维的树状数组即可
显然N维的线段树是相当恐怖的东西 相比而言 N维的树状数组就优美了许多
要理解树状数组 看几张图即可
具体的算法可以到baidu去找 三个函数才几行话{Lowbit(),Getsum(),Change()}
各人的理解方式可能不同 自己理解出来的才是最好的
提示一下 树状数组的核心是二进制思想
相信大家小时候都做过这个这个问题 任何一个数可以拆成不同的2的幂的和
树状数组通俗的讲就是这个道理
由于拆出的数的个数不超过Log2N个 树状数组的复杂度就是O(Log2N)
树状数组的入门问题
Pku 2352 http://poj.org/problem?id=2352
算法也很简单
把所有星星都投影到x轴上
由于给的星星是有顺序的(从下到上 从左到右)
每次插入一个星星 就累加当前的统计值 最后输出即可
const maxn=15000;
maxm=32001;
var x,y:array[1..maxn]of longint;
c:array[1..maxm]of longint;
h:array[0..maxn-1]of longint;
i,n,m:longint;
function lowbit(v:longint):longint;
begin
lowbit:=v and -v;
end;
procedure insert(x:longint);
var y:longint;
begin
y:=x;
while y<=m do
begin
c[y]:=c[y]+1;
y:=y+lowbit(y);
end;
end;
function query(x:longint):longint;
var ans,y:longint;
begin
y:=x;
ans:=0;
while y>0 do
begin
ans:=ans+c[y];
y:=y-lowbit(y);
end;
query:=ans;
end;
begin
assign(input,'star.in'); reset(input);
assign(output,'star.out'); rewrite(output);
readln(n);
m:=0;
for i:=1 to n do
begin
readln(x[i],y[i]);
if m<x[i] then m:=x[i];
end;
m:=m+1;
for i:=1 to n do
begin
inc(h[query(x[i]+1)]);
insert(x[i]+1);
end;
for i:=0 to n-1 do
writeln(h[i]);
close(input); close(output);
end.
树状数组很优美 但是这优美不是轻易能领略的 需要进行转化
原本树状数组支持的操作是修改一个数 查询区间和
我们有时候会碰到查询一个数 修改区间值的问题
同样可以通过转化来用树状数组解决
对于查询一个数a[i]我们转化为getsum(i) 即把a[i]转化为长为i前缀和
而修改区间我们如下图操作
修改[x,y] 我们就change(x,1) change(y+1,-1)
不难发现 对[x,y]内的数getsum就会+1 否则是不变的 这就相当于区间修改了
树状数组可以轻易的扩展到2维 3维
看两个这样的问题
Pku 2155 http://poj.org/problem?id=2155
Hdu 3584 http://acm.hdu.edu.cn/showproblem.php?pid=3584
分别是树状数组的二维和三维延伸
题意差不多
给定0 1阵 支持取反一个区间 查询单个值
对于取反操作 我们记录取反的次数 然后取2的模就可以反映当前的值了
这样问题就是支持区间修改和查询单值的问题
如果是一维的问题直接使用上面所说的方法就可以解决
现在是二维 三维了
二维的树状数组只是加了一维 操作只是多了一重循环
具体的操作可以baidu而知 不再赘述
我们可以如下图对c[][]进行修改 然后getsum(i,j)来求当前a[i,j]的值
三维需要画一个好一点的图 画出来了很有成就感 试一试吧
代码很好懂 具体看代码
Matrix
const maxn=1000;
var c:array[1..maxn,1..maxn]of longint;
i,x1,y1,x2,y2,z,n,m:longint;
ch:char;
function lowbit(x:longint):longint;
begin
lowbit:=x and -x;
end;
procedure chg(x,y,z:longint);
var i,j:longint;
begin
i:=x;
while i<=n do
begin
j:=y;
while j<=n do
begin
c[i][j]:=c[i][j]+z;
j:=j+lowbit(j);
end;
i:=i+lowbit(i);
end;
end;
function gs(x,y:longint):longint;
var ans,i,j:longint;
begin
ans:=0;
i:=x;
while i>0 do
begin
j:=y;
while j>0 do
begin
ans:=ans+c[i][j];
j:=j-lowbit(j);
end;
i:=i-lowbit(i);
end;
gs:=ans;
end;
begin
assign(input,'matrix.in'); reset(input);
assign(output,'matrix.out'); rewrite(output);
readln(z);
while z<>0 do
begin
dec(z);
readln(n,m);
for i:=1 to m do
begin
read(ch);
case ch of
'C':
begin
readln(x1,y1,x2,y2);
chg(x1,y1,1);
chg(x1,y2+1,-1);
chg(x2+1,y1,-1);
chg(x2+1,y2+1,1);
end;
'Q':
begin
readln(x1,y1);
writeln(gs(x1,y1)and 1);
end;
end;
end;
writeln;
fillchar(c,sizeof(c),0);
end;
close(input); close(output);
end.
Cube
const maxn=100;
var i,n,m,ch,x1,x2,y1,y2,z1,z2:longint;
c:array[1..maxn,1..maxn,1..maxn]of longint;
function lowbit(x:longint):longint;
begin
lowbit:=x and -x;
end;
procedure chg(x,y,z,ch:longint);
var i,j,k:longint;
begin
i:=x;
while i<=n do
begin
j:=y;
while j<=n do
begin
k:=z;
while k<=n do
begin
c[i][j][k]:=c[i][j][k]+ch;
k:=k+lowbit(k);
end;
j:=j+lowbit(j);
end;
i:=i+lowbit(i);
end;
end;
function gs(x,y,z:longint):longint;
var ans,i,j,k:longint;
begin
ans:=0;
i:=x;
while i>0 do
begin
j:=y;
while j>0 do
begin
k:=z;
while k>0 do
begin
ans:=ans+c[i][j][k];
k:=k-lowbit(k);
end;
j:=j-lowbit(j);
end;
i:=i-lowbit(i);
end;
gs:=ans;
end;
begin
assign(input,'cube.in'); reset(input);
assign(output,'cube.out'); rewrite(output);
while not eof do
begin
readln(n,m);
for i:=1 to m do
begin
read(ch);
case ch of
0:
begin
readln(x1,y1,z1);
writeln(gs(x1,y1,z1)and 1);
end;
1:
begin
readln(x1,y1,z1,x2,y2,z2);
chg(x1,y1,z1,1);
chg(x1,y2+1,z1,-1);
chg(x2+1,y1,z1,-1);
chg(x2+1,y2+1,z1,1);
chg(x1,y1,z2+1,-1);
chg(x1,y2+1,z2+1,1);
chg(x2+1,y1,z2+1,1);
chg(x2+1,y2+1,z2+1,-1);
end;
end;
end;
fillchar(c,sizeof(c),0);
end;
close(input); close(output);
end.
BOB HAN 原创 转载请注明出处 http://www.cnblogs.com/Booble/
本文图片来自 http://hi.baidu.com/edelweisszf/blog/item/dd8a2fa2dfc60babcbefd013.html
(写的也很好 建议一起看)
posted on 2010-10-24 20:35 Master_Chivu 阅读(2275) 评论(1) 编辑 收藏 举报