POJ-2155 简单二维线段树 区间翻转
Matrix
| Time Limit: 3000MS | Memory Limit: 65536K | |
| Total Submissions: 10544 | Accepted: 3945 |
Description
Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1 <= i, j <= N).
We can change the matrix in the following way. Given a rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2), we change all the elements in the rectangle by using "not" operation (if it is a '0' then change it into '1' otherwise change it into '0'). To maintain the information of the matrix, you are asked to write a program to receive and execute two kinds of instructions.
1. C x1 y1 x2 y2 (1 <= x1 <= x2 <= n, 1 <= y1 <= y2 <= n) changes the matrix by using the rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2).
2. Q x y (1 <= x, y <= n) querys A[x, y].
We can change the matrix in the following way. Given a rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2), we change all the elements in the rectangle by using "not" operation (if it is a '0' then change it into '1' otherwise change it into '0'). To maintain the information of the matrix, you are asked to write a program to receive and execute two kinds of instructions.
1. C x1 y1 x2 y2 (1 <= x1 <= x2 <= n, 1 <= y1 <= y2 <= n) changes the matrix by using the rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2).
2. Q x y (1 <= x, y <= n) querys A[x, y].
Input
The first line of the input is an integer X (X <= 10) representing the number of test cases. The following X blocks each represents a test case.
The first line of each block contains two numbers N and T (2 <= N <= 1000, 1 <= T <= 50000) representing the size of the matrix and the number of the instructions. The following T lines each represents an instruction having the format "Q x y" or "C x1 y1 x2 y2", which has been described above.
The first line of each block contains two numbers N and T (2 <= N <= 1000, 1 <= T <= 50000) representing the size of the matrix and the number of the instructions. The following T lines each represents an instruction having the format "Q x y" or "C x1 y1 x2 y2", which has been described above.
Output
For each querying output one line, which has an integer representing A[x, y].
There is a blank line between every two continuous test cases.
There is a blank line between every two continuous test cases.
Sample Input
1 2 10 C 2 1 2 2 Q 2 2 C 2 1 2 1 Q 1 1 C 1 1 2 1 C 1 2 1 2 C 1 1 2 2 Q 1 1 C 1 1 2 1 Q 2 1
Sample Output
1 0 0 1
该题从操作上来讲是极像HDU敌兵布阵的,因为这里也是对点操作(指询问操作),在写一维线段树的时候,知道这时该种数据结构中最简单的操作,因为其未触及复杂的搜索更新操作,以及Lazy思想的处理。一直写的就是区间树,点树无视,所以虽然给定的是一个点,还是看作一条线段,只是区间为半开半闭而已。理由是对某条边而言, N 个点只有 N - 1个线段,所以要虚设一个点。
该题是区间的翻转,之前遇到过染色问题,不小心将这两者混淆了,其实两者是有些区别的。
染色(Lazy操作):给定一个区间就把这个区间的信息强制统一,其孩子节点在下一次直接对其操作前所含信息作废。(一个节点的属性由最后一次相关的操作决定)其性质在往下搜索的过程中由其上面的节点就可以代替了。因此每个节点就有个标记,标记该节点是否具有代表性,是否所保留的信息是作废的。如果某一次更新打破了某个节点的代表性,那么就会有以下操作:将该节点的标记取消,取消之前将信息传递给他的两个孩子,这个操作还没有改变这棵数的性质,并开启两个孩子的标记,然后再在两个孩子上进行操作,非常巧妙的操作。
翻转:给定一个区间,将为 0 的区间设为 1,将为 1 的区间设置为 0 。(一个节点的属性由针对该区间操作的次数的奇偶性决定)与前者不同,如果给定一个更新的区间,同样的,遇到刚好满足左右边界的区间进行一次操作,这次操作的意义是 “该区间上的操作数加上 1 ”,此时,其孩子节点的信息并没作废,而是同样具有统计意义,也就是每次询问某个节点的时候是要一问到底的。与查看颜色不同,不会因中途得到信息而立即退出。
二维线段树对应的操作均有两个,对应不同的维,每一个一维节点下有一棵线段数,在空间上的开销是比较大的。这也算是以空间换时间吧。写的时候犯了几个小的错误,给定的区间应该是和所给节点的左右边界去比。对于一个点而言,区间长度为一,只有要么在左树要么在右树两种情况。
代码如下:
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define LSON p << 1
#define RSON p << 1 | 1
#define MID( x, y ) (x) + (y) >> 1
#define TWO( x, y ) (x) + (y) << 1
#define M( x, y ) memset( (x), (y), sizeof(x) )
using namespace std;
struct node
{
int u, d, val;
}n[2605][2605];
struct Node
{
int l, r;
node *next;
}N[2605];
int M, Q, ans;
void y_build( node *r, int p, int u, int d )
{
r[p].u = u, r[p].d = d, r[p].val = 0;
if( d - u > 1 )
{
int m = MID( d, u );
y_build( r, LSON, u, m );
y_build( r, RSON, m, d );
}
}
void build( int p, int l, int r )
{
N[p].l = l, N[p].r = r, N[p].next = n[p];
if( r - l > 1 )
{
int m = MID( l, r );
build( LSON, l, m );
build( RSON, m, r );
}
y_build( n[p], 1, 1, M + 1 );
}
void y_modify( node *r, int p, int u, int d )
{
if( r[p].u == u && r[p].d == d )
{
r[p].val ^= 1;
return;
}
int m = MID( r[p].u , r[p].d );
if( m >= d )
y_modify( r, LSON, u, d );
else if( m <= u )
y_modify( r, RSON, u, d );
else
{
y_modify( r, LSON, u, m );
y_modify( r, RSON, m, d );
}
}
void modify( int p, int l, int r, int u, int d )
{
if( N[p].l == l && N[p].r == r )
{
y_modify( N[p].next, 1, u, d );
return;
}
int m = MID( N[p].l, N[p].r );
if( m >= r )
modify( LSON, l, r, u, d );
else if( m <= l )
modify( RSON, l, r, u, d );
else
{
modify( LSON, l, m, u, d );
modify( RSON, m, r, u, d );
}
}
void y_cal( node *r, int p, int u, int d )
{
if( r[p].u <= u && r[p].d >= d )
{
ans ^= r[p].val;
if( r[p].d - r[p].u == 1 )
return;
}
int m = MID( r[p].u, r[p].d );
if( m >= d )
y_cal( r, LSON, u, d );
else if( m <= u )
{
y_cal( r, RSON, u, d );
}
}
void cal( int p, int l, int r, int u, int d )
{
if( N[p].l <= l && N[p].r >= r )
{
y_cal( N[p].next, 1, u, d );
if( N[p].r - N[p].l == 1 )
return;
}
int m = MID( N[p].l, N[p].r );
if( m >= r )
cal( LSON, l, r, u, d );
else if( m <= l )
cal( RSON, l, r, u, d );
}
int main()
{
int T;
scanf( "%d", &T );
for( int t = 1; t <= T; ++t )
{
char op[5];
int x1, x2, y1, y2;
scanf( "%d %d", &M, &Q );
build( 1, 1, M + 1 );
for( int i = 0; i < Q; ++i )
{
scanf( "%s", op );
if( op[0] == 'C' )
{
scanf( "%d %d %d %d", &x1, &y1, &x2, &y2 );
modify( 1, x1, x2 + 1, y1, y2 + 1 );
}
else
{
ans = 0;
scanf( "%d %d", &x1, &y1 );
cal( 1, x1, x1 + 1, y1, y1 + 1 );
printf( "%d\n", ans );
}
}
if( t < T )
puts( "" );
}
return 0;
}


浙公网安备 33010602011771号