省选之后好久没做题了呀。。。
二维线段树其实就是把线段树的节点变为一棵线段树,以坐标轴为例,先查询x轴范围,再在表示x轴节点内查询y轴节点,时间复杂度维持在o(logn*logn)内。
2155这道题是在坐标轴中,动态修改矩阵值(xor),询问某一a(x,y)是1或0。
由于是二维,想到了二维线段树,由于涉及区间修改,单点查询,用到了标记永久化。
二维线段树上面已经介绍过了,标记永久化则是在zkw线段树中非常好用的手段,将信息存在尽可能靠近根部位置(zkw的自底向上可以很快找到这一位置)不再下放,询问的时候只需根据叶子到根的路径上的每一个标记进行修改就可以了。
关于zkw线段树可以看论文,或我之前写的几篇文章。具体实现参见程序。
var b:array[1..2048,1..2048]of integer;
n,m,t,m1,ans:longint;
procedure operate2(k,y1,y2:longint);
var l,r:longint;
begin
l:=y1+m1-1;r:=y2+m1+1;
while not(l xor r=1) do begin
if l and 1=0 then b[k,l+1]:=b[k,l+1] xor 1;
if r and 1=1 then b[k,r-1]:=b[k,r-1] xor 1;
l:=l>>1;r:=r>>1
end
end;
procedure operate(x1,y1,x2,y2:longint);
var l,r:longint;
begin
l:=x1+m1-1;r:=x2+m1+1;
while not(l xor r=1) do begin
if l and 1=0 then operate2(l+1,y1,y2);
if r and 1=1 then operate2(r-1,y1,y2);
l:=l>>1;r:=r>>1
end
end;
procedure ask2(k,y1:longint);
begin
y1:=y1+m1;
while y1<>0 do begin
ans:=ans xor b[k,y1];
y1:=y1>>1
end
end;
procedure ask(x1,y1:longint);
begin
x1:=x1+m1;
while x1<>0 do begin
ask2(x1,y1);
x1:=x1>>1;
end
end;
procedure origin;
begin
fillchar(b,sizeof(b),0);
m1:=1;
while m1<=n+2 do m1:=m1<<1;m1:=m1-1
end;
procedure init;
var i,x1,y1,x2,y2:longint;
q,q1:char;
begin
readln(n,m);
origin;
for i:=1 to m do begin
read(q,q1);
if q='C' then begin
readln(x1,y1,x2,y2);
operate(x1,y1,x2,y2)
end
else begin
readln(x1,y1);ans:=0;
ask(x1,y1);
writeln(ans)
end
end;
writeln;
end;
begin
//assign(input,'2155.in');reset(input);
readln(t);
for t:=1 to t do init;
//close(input)
end.