这题的要求和树状数组的使用方法恰好相反,改变的是一个区间,查询的反而是一个点。我们先看一维的情况。
首先定义
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 ;
}