这题的要求和树状数组的使用方法恰好相反,改变的是一个区间,查询的反而是一个点。我们先看一维的情况。
首先定义
Up(a)={a1=a,a2=a1+lowbit(a1),a3=a2+lowbit(a2) ... }
Down(a)={a1=a,a2=a1-lowbit(a1),a3=a2-lowbit(a2) ... }
为了方便讨论,只说明初始化后的第一次“C a b”和“Q c”操作:
对于命令“C a b”,我们分别调用函数down(b,1)和down(a-1,-1),将下标属于集合Down(b)的C中的元素+1,下标属于集合Down(a-1)的C中的元素-1,联系到通常树状数组的求和为down(b)-down(a-1),这里只不过把取值操作转变为对值的修改;
然后分情况讨论函数up(c)如何对点进行查询,可以发现对于任意的a<=b,Up(a)与Down(b)的交集只有一个元素。
因此
当a<c<=b时,Up(c)与Down(a-1)无交集,与Down(b)有交集且交集内只有一个元素,由之前的修改可知该元素为1,故返回1;
当b<c时,Up(c)与Down(b)无交集,故返回0;
当c<=a时,Up(c)分别与Down(b)和Down(a-1)构成一个元素的交集,其元素分别为-1和1,抵消后返回0;
此时返回值就是点c处的值。
了解如何获得第一次修改后的询问结果后,只要将简单的返回值变更为对下标属于集合Up(c)的C中元素的累加值,就能得到多次修改后的询问结果,然后扩展至二维即可。
/*
Source Code
Problem: 2155 User: zgmf_x20a
Memory: 4160K Time: 438MS
Language: C++ Result: Accepted
*/
#include
<
iostream
>
#include
<
algorithm
>
using
namespace
std;
#define
MAXN 1005
#define
clr(x) memset(x,0,sizeof(x))
int
c[MAXN][MAXN],n,query;
inline
int
lowbit(
int
x){
return
x
&
(
-
x);
}
void
down(
int
x,
int
y,
int
tt){
int
i
=
x,j
=
y;
while
(i
>
0
){
j
=
y;
while
(j
>
0
){
c[i][j]
+=
tt;
j
-=
lowbit(j);
}
i
-=
lowbit(i);
}
}
int
up(
int
x,
int
y){
int
i
=
x,j
=
y,res
=
0
;
while
(i
<=
n){
j
=
y;
while
(j
<=
n){
res
+=
c[i][j];
j
+=
lowbit(j);
}
i
+=
lowbit(i);
}
return
res;
}
int
main(){
int
T,x1,y1,x2,y2;
char
str[
3
];
scanf(
"
%d
"
,
&
T);
while
(T
--
){
clr(c);
scanf(
"
%d%d
"
,
&
n,
&
query);
while
(query
--
){
scanf(
"
%s
"
,str);
if
(str[
0
]
==
'
C
'
){
scanf(
"
%d%d%d%d
"
,
&
x1,
&
y1,
&
x2,
&
y2);
down(x2,y2,
1
);
down(x1
-
1
,y2,
-
1
);
down(x2,y1
-
1
,
-
1
);
down(x1
-
1
,y1
-
1
,
1
);
}
else
{
scanf(
"
%d%d
"
,
&
x1,
&
y1);
printf(
"
%d\n
"
,up(x1,y1)
%
2
);
}
}
printf(
"
\n
"
);
}
return
0
;
}
另附二维线段树代码
/*
Source Code
Problem: 2155 User: zgmf_x20a
Memory: 56440K Time: 1922MS
Language: C++ Result: Accepted
*/
#include
<
iostream
>
using
namespace
std;
#define
MAXN 1001
#define
clr(x) memset(x,0,sizeof(x))
int
n,m;
struct
Node{
int
l,r,cnt;
};
class
SegTree{
Node nod[
3
*
MAXN];
public
:
void
BuildTree(
int
u,
int
l,
int
r){
nod[u].l
=
l;
nod[u].r
=
r;
nod[u].cnt
=
0
;
if
(l
==
r)
return
;
BuildTree(
2
*
u,l,(l
+
r)
/
2
);
BuildTree(
2
*
u
+
1
,(l
+
r)
/
2
+
1
,r);
}
void
Insert(
int
u,
int
l,
int
r){
if
(l
<=
nod[u].l
&&
nod[u].r
<=
r){
nod[u].cnt
++
;
return
;
}
if
(l
<=
nod[
2
*
u].r)
Insert(
2
*
u,l,r);
if
(r
>=
nod[
2
*
u
+
1
].l)
Insert(
2
*
u
+
1
,l,r);
}
int
Query(
int
u,
int
l,
int
r,
int
sum){
sum
+=
nod[u].cnt;
if
(l
<=
nod[u].l
&&
nod[u].r
<=
r)
return
sum;
int
res
=
0
;
if
(l
<=
nod[
2
*
u].r)
res
+=
Query(
2
*
u,l,r,sum);
if
(r
>=
nod[
2
*
u
+
1
].l)
res
+=
Query(
2
*
u
+
1
,l,r,sum);
return
res;
}
};
struct
_2DNode{
SegTree tre;
//
二维线段树中每个区间被翻转的次数用一维线段树统计
int
l,r;
};
class
_2DSegTree{
_2DNode _2Dnod[
3
*
MAXN];
public
:
void
_2DBuildTree(
int
u,
int
xl,
int
xr,
int
yl,
int
yr){
_2Dnod[u].l
=
xl;
_2Dnod[u].r
=
xr;
_2Dnod[u].tre.BuildTree(
1
,yl,yr);
if
(xl
==
xr)
return
;
_2DBuildTree(
2
*
u,xl,(xl
+
xr)
/
2
,yl,yr);
_2DBuildTree(
2
*
u
+
1
,(xl
+
xr)
/
2
+
1
,xr,yl,yr);
}
void
_2DInsert(
int
u,
int
xl,
int
xr,
int
yl,
int
yr){
if
(xl
<=
_2Dnod[u].l
&&
_2Dnod[u].r
<=
xr){
_2Dnod[u].tre.Insert(
1
,yl,yr);
return
;
}
if
(xl
<=
_2Dnod[
2
*
u].r)
_2DInsert(
2
*
u,xl,xr,yl,yr);
if
(xr
>=
_2Dnod[
2
*
u
+
1
].l)
_2DInsert(
2
*
u
+
1
,xl,xr,yl,yr);
}
int
_2DQuery(
int
u,
int
xl,
int
xr,
int
yl,
int
yr,
int
sum){
sum
+=
_2Dnod[u].tre.Query(
1
,yl,yr,
0
);
if
(xl
<=
_2Dnod[u].l
&&
_2Dnod[u].r
<=
xr)
return
sum;
int
res
=
0
;
if
(xl
<=
_2Dnod[
2
*
u].r)
res
+=
_2DQuery(
2
*
u,xl,xr,yl,yr,sum);
if
(xr
>=
_2Dnod[
2
*
u
+
1
].l)
res
+=
_2DQuery(
2
*
u
+
1
,xl,xr,yl,yr,sum);
return
res;
}
};
_2DSegTree tr;
int
main(){
int
i,T,xl,xr,yl,yr;
char
str[
3
];
scanf(
"
%d
"
,
&
T);
while
(T
--
){
scanf(
"
%d%d
"
,
&
n,
&
m);
tr._2DBuildTree(
1
,
1
,n,
1
,n);
for
(i
=
0
;i
<
m;i
++
){
scanf(
"
%s
"
,str);
if
(str[
0
]
==
'
C
'
){
scanf(
"
%d%d%d%d
"
,
&
xl,
&
yl,
&
xr,
&
yr);
tr._2DInsert(
1
,xl,xr,yl,yr);
}
else
{
scanf(
"
%d%d
"
,
&
xl,
&
yl);
printf(
"
%d\n
"
,tr._2DQuery(
1
,xl,xl,yl,yl,
0
)
%
2
);
}
}
printf(
"
\n
"
);
}
return
0
;
}