POJ 2155
题目是说对一个01矩形区间有两种操作:
一是置反某一块区间点(a,b)(左上角)--->点(c,d)(右下角)(0变1,1变0)
二是询问[i][j]位置处的当前值是0还是1。
这题用二维线段树来做。其实就是线段树套线段树。
首先以x轴为下标建立一颗线段树,在这棵线段树的每个节点建立一棵以y轴为下标的线段树。
A[i][j]表示在x轴线段树上i节点代表的x轴区间[x1,x2]和在y轴线段树上j节点代表的y轴区间[y1,y2]构成的矩形被修改了奇数次还是偶数次——即点(x1,y1)左上角——>点(x2,y2)右下角的矩形以整个区域为单位被修改次数的奇偶情况。
修改时打标记即可,标记无须下传,因为A[i][j]就表示以点(x1,y1)左上角——>点(x2,y2)右下角的矩形的整体的修改状况。
询问时需要注意:包含所询问的点的所有矩形A[i][j]都得算进去。
(复习时须看代码理解)
//poj2155
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for (int i = a;i <= b;i ++)
using namespace std;
const int maxn = 1005;
int T,N,Q,Ans;
bool A[maxn*4][maxn*4];
void Modify_y(int i,int j,int l,int r,int x,int y)
{
if (x <= l && r <= y)
{
A[i][j] ^= 1;
return;
}
int mid = (l + r) >> 1;
if (x <= mid) Modify_y(i,j*2,l,mid,x,y);
if (y > mid) Modify_y(i,j*2+1,mid+1,r,x,y);
}
void Modify_x(int z,int l,int r,int x1,int x2,int y1,int y2)
{
if (x1 <= l && r <= x2)
{
Modify_y(z,1,1,N,y1,y2);
return;
}
int mid = (l + r) >> 1;
if (x1 <= mid) Modify_x(z*2,l,mid,x1,x2,y1,y2);
if (x2 > mid) Modify_x(z*2+1,mid+1,r,x1,x2,y1,y2);
}
void Query_y(int i,int j,int l,int r,int y)
{
Ans ^= A[i][j];
if (l == r) return;
int mid = (l + r) >> 1;
if (y <= mid) Query_y(i,j*2,l,mid,y);
if (y > mid) Query_y(i,j*2+1,mid+1,r,y);
}
void Query_x(int z,int l,int r,int x,int y)
{
Query_y(z,1,1,N,y);
if (l == r) return;
int mid = (l + r) >> 1;
if (x <= mid) Query_x(z*2,l,mid,x,y);
if (x > mid) Query_x(z*2+1,mid+1,r,x,y);
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d",&T);
while (T --)
{
scanf("%d%d",&N,&Q);
fo(i,1,4*N) fo(j,1,4*N) A[i][j] = 0;
while (Q --)
{
char ch;
do ch = getchar(); while (ch < 'A' || ch > 'Z');
if (ch == 'C')
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
Modify_x(1,1,N,x1,x2,y1,y2);
} else
{
int x,y;
scanf("%d%d",&x,&y);
Ans = 0;
Query_x(1,1,N,x,y);
printf("%d\n",Ans);
}
}
if (T) printf("\n");
}
return 0;
}