| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
Re:二维线段树In Reply To:二维线段树 Posted by:wwwaaannngggrs at 2011-04-08 09:40:03 二维线段树
把线段树转移到二维还是用的一维时的思想。
一维的时候父区间分为两个子区间,
那么二维的时候是不是也可以把父矩阵分为四个子矩阵呢?
应该是可以的。
那么仿照一维的写法:
build(k*4+1,lx,ly,xmid,ymid);
build(k*4+2,xmid+1,ly,rx,ymid);
build(k*4+3,lx,ymid+1,xmid,ry);
build(k*4+4,xmid+1,ymid+1,rx,ry);
if (lx<=g[k].xmid)and(ly<=g[k].ymid) then insert(k*4+1,lx,ly,rx,ry,coo);
if (rx>g[k].xmid)and(ly<=g[k].ymid) then insert(k*4+2,lx,ly,rx,ry,coo);
If (lx<=g[k].xmid)and(ry>g[k].ymid) then insert(k*4+3,lx,ly,rx,ry,coo);
if (rx>g[k].xmid)and(ry>g[k].ymid) then insert(k*4+4,lx,ly,rx,ry,coo);
那么差不多是可行的。
可是会出现一种特殊情况,即大小为1×2的矩形
它不是单个的子矩阵,也不是有四个孩子的父矩阵。它比较异类。
所以建树的时候我加了一句特判(不然216):
if (lx<>rx)or(ly<>ry) then build(k*4+1,lx,ly,xmid,ymid);
if lx<>rx then build(k*4+2,xmid+1,ly,rx,ymid);
if ly<>ry then build(k*4+3,lx,ymid+1,xmid,ry);
if (lx<>rx)and(ly<>ry) then build(k*4+4,xmid+1,ymid+1,rx,ry);
然后pku1656这题的样例就轻松过掉了。
可是去网上测总是Runtime Error
把Discuss上的那段C++的二维线段树看了又看也查不出错。
调了一个下午后 开始自己生成随机数据写。
果真是216了。 发生在insert操作里。
原因是在insert是产生了非法节点,即大小为1×2的矩形的非法孩子。
比如
(84,58)
(85,58)
这个矩形是当前搜到的矩形。而它的下半部分在插入范围之内,上半部分不在,那么我们就需要找它的子区间,这个时候如果不判断又会去找它右下角的孩子,但实际上它只在左上角和左下角有孩子,那么进入非法的孩子区间之后,就会看到216.
想来想去没有什么好办法,就写了一个暴力的判断该区间是否为合法区间的v[]布尔数组。
这样所有操作再添上判断是否合法就可以AC了。
至于楼主的那段C++代码的神奇之处有三点
它不建树预处理 2.插入和求和操作时一并计算当前区间各点坐标。可节省空间。
综合上面两点神奇之处就可以得到第三点神奇之处,即使遇到非法区间也能全身而退。
最多进入非法状态一层就可以在正常的判断下退出过程。有兴趣的可以模拟下。
下面是我的代码(P写的,加暴力判断,比较丑):
type gtree=record
lx,ly,xmid,rx,ry,ymid,coo,sum:longint;
end;
var g:array[0..30000] of gtree;
v:array[0..30000] of boolean;
i,question,lx,ly,L:longint;
x:char;
procedure build(k,lx,ly,rx,ry:longint);
begin
g[k].lx:=lx; g[k].ly:=ly; g[k].rx:=rx; g[k].ry:=ry;
g[k].xmid:=(lx+rx) div 2; g[k].ymid:=(ly+ry) div 2;
g[k].coo:=0; g[k].sum:=0; v[k]:=true;
with g[k] do
begin
if (lx<>rx)or(ly<>ry) then build(k*4+1,lx,ly,xmid,ymid);
if lx<>rx then build(k*4+2,xmid+1,ly,rx,ymid);
if ly<>ry then build(k*4+3,lx,ymid+1,xmid,ry);
if (lx<>rx)and(ly<>ry) then build(k*4+4,xmid+1,ymid+1,rx,ry);
end;
end;
procedure push(k:longint);
begin
if g[k].coo=-1 then exit;
if v[k*4+1] then begin
g[k*4+1].coo:=g[k].coo;
g[k*4+1].sum:=(g[k*4+1].rx-g[k*4+1].lx+1)*(g[k*4+1].ry-g[k*4+1].ly+1)*g[k].coo;
end;
if v[k*4+2] then begin
g[k*4+2].coo:=g[k].coo;
g[k*4+2].sum:=(g[k*4+2].rx-g[k*4+2].lx+1)*(g[k*4+2].ry-g[k*4+2].ly+1)*g[k].coo;
end;
if v[k*4+3] then begin
g[k*4+3].coo:=g[k].coo;
g[k*4+3].sum:=(g[k*4+3].rx-g[k*4+3].lx+1)*(g[k*4+3].ry-g[k*4+3].ly+1)*g[k].coo;
end;
if v[k*4+4] then begin
g[k*4+4].coo:=g[k].coo;
g[k*4+4].sum:=(g[k*4+4].rx-g[k*4+4].lx+1)*(g[k*4+4].ry-g[k*4+4].ly+1)*g[k].coo;
end;
g[k].coo:=-1;
end;
procedure update(k:longint);
begin
g[k].sum:=0;
if v[k*4+1] then inc(g[k].sum,g[k*4+1].sum);
if v[k*4+2] then inc(g[k].sum,g[k*4+2].sum);
if v[k*4+3] then inc(g[k].sum,g[k*4+3].sum);
if v[k*4+4] then inc(g[k].sum,g[k*4+4].sum);
end;
procedure insert(k,lx,ly,rx,ry,coo:longint);
begin
if (lx<=g[k].lx)and(g[k].rx<=rx)and(ly<=g[k].ly)and(g[k].ry<=ry)
then begin
g[k].coo:=coo;
g[k].sum:=(g[k].rx-g[k].lx+1)*(g[k].ry-g[k].ly+1)*g[k].coo;
end
else begin
push(k);
if (v[k*4+1])and(lx<=g[k].xmid)and(ly<=g[k].ymid) then insert(k*4+1,lx,ly,rx,ry,coo);
if (v[k*4+2])and(rx>g[k].xmid)and(ly<=g[k].ymid) then insert(k*4+2,lx,ly,rx,ry,coo);
if (v[k*4+3])and(lx<=g[k].xmid)and(ry>g[k].ymid) then insert(k*4+3,lx,ly,rx,ry,coo);
if (v[k*4+4])and(rx>g[k].xmid)and(ry>g[k].ymid) then insert(k*4+4,lx,ly,rx,ry,coo);
update(k);
end;
end;
function getsum(k,lx,ly,rx,ry:longint):longint;
begin
getsum:=0;
if (lx<=g[k].lx)and(g[k].rx<=rx)and(ly<=g[k].ly)and(g[k].ry<=ry)
then inc(getsum,g[k].sum)
else begin
push(k);
if (v[k*4+1])and(lx<=g[k].xmid)and(ly<=g[k].ymid) then inc(getsum,getsum(k*4+1,lx,ly,rx,ry));
if (v[k*4+2])and(rx>g[k].xmid)and(ly<=g[k].ymid) then inc(getsum,getsum(k*4+2,lx,ly,rx,ry));
if (v[k*4+3])and(lx<=g[k].xmid)and(ry>g[k].ymid) then inc(getsum,getsum(k*4+3,lx,ly,rx,ry));
if (v[k*4+4])and(rx>g[k].xmid)and(ry>g[k].ymid) then inc(getsum,getsum(k*4+4,lx,ly,rx,ry));
end;
end;
begin
fillchar(v,sizeof(v),false);
build(0,1,1,101,101);
readln(question);
for i:=1 to question do
begin
read(x);
case x of
'B':begin
read(x);read(x);read(x);read(x);
readln(lx,ly,L);
insert(0,lx,ly,lx+L-1,ly+L-1,1);
end;
'W':begin
read(x);read(x);read(x);read(x);
readln(lx,ly,L);
insert(0,lx,ly,lx+L-1,ly+L-1,0);
end;
'T':begin
read(x);read(x);read(x);
readln(lx,ly,L);
writeln(getsum(0,lx,ly,lx+L-1,ly+L-1));
end;
end;
end;
end.
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator