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; }