POJ2155 Matrix二维线段树经典题

题目链接

二维树状数组

 1 #include<iostream>
 2 #include<math.h>
 3 #include<algorithm>
 4 #include<stdlib.h>
 5 using namespace std;
 6 #define ll long long
 7 #define re(i,n) for(int i=0;i<n;i++)
 8 const int maxn = 1007;
 9 int c[maxn][maxn];
10 int n, q;
11 int lowbit(int x){
12     return x&(-x);
13 }
14 void update(int x, int y){
15     for (int i = x; i >0; i-=lowbit(i))
16         for (int j = y; j >0; j -= lowbit(j))
17             c[i][j] ^= 1;
18 }
19 int query(int x, int y){
20     int ans = 0;
21     for (int i = x; i <= n; i+=lowbit(i))
22     for (int j = y; j <= n; j += lowbit(j)){
23         ans ^= c[i][j];
24     }
25     return ans;
26 }
27 int main(){
28     //freopen("in.txt", "r", stdin);
29     int T; cin >> T;
30     while (T--){
31         scanf("%d%d", &n, &q);
32         memset(c, 0, sizeof(c));
33         while (q--){
34             char op[2]; scanf("%s", op);
35             if (op[0] == ‘Q‘){
36                 int x, y; scanf("%d%d", &x, &y);
37                 printf("%d\n", query(x, y));
38             }
39             else{
40                 int fx, fy, tx, ty; scanf("%d%d%d%d", &fx, &fy, &tx, &ty);
41                 if (fx > tx)swap(fx, tx); if (fy > ty)swap(fy, ty);
42                 fx--, fy--;
43                 update(fx, fy);
44                 update(tx, ty);
45                 update(fx, ty);
46                 update(tx, fy);
47             }
48         }
49         puts("");
50     }
51     return 0;
52 }

二维线段树

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<string.h>
 4 using namespace std;
 5 #define ll long long
 6 #define re(i,n) for(int i=0;i<n;i++)
 7 #define ls(x) x<<1,f,mid
 8 #define rs(x) x<<1|1,mid+1,t
 9 const int maxn = 1005;
10 int n, q;
11 int fx, fy, tx, ty, x, y;
12 int ans;
13 bool a[maxn << 2][maxn << 2];
14 void updatey(int i, int j, int f, int t){
15     if (fy <= f&&ty >= t){
16         a[i][j] ^= 1;
17         return;
18     }
19     int mid = (f + t) >> 1;
20     if (fy <= mid)updatey(i,ls(j));
21     if (ty > mid)updatey(i, rs(j));
22 }
23 void updatex(int i, int f, int t){
24     if (fx<=f&&tx>=t){
25         updatey(i, 1, 1, n);
26         return;
27     }
28     int mid = (f + t) >> 1;
29     if (fx <= mid)updatex(ls(i));
30     if (tx > mid)updatex(rs(i));
31 }
32 void queryy(int i, int j, int f, int t){
33     ans += a[i][j];
34     if (f == t)return;
35     int mid = (f + t) >> 1;
36     if (y > mid)queryy(i,rs(j));
37     else queryy(i, ls(j));
38 }
39 void queryx(int i, int f, int t){
40     queryy(i, 1, 1, n);
41     if (f == t)return;
42     int mid = (f + t) >> 1;
43     if (x > mid)queryx(rs(i));
44     else queryx(ls(i));
45 }
46 int main(){
47     //freopen("in.txt", "r", stdin);
48     int T; cin >> T;
49     while (T--){
50         scanf("%d%d", &n, &q);
51         memset(a, 0, sizeof(a));
52         /*应该用memset,用for循环一定要注意初始化的不是n,而是全部.
53         公元2015年9.20日在于此坑.
54         re(i, n + 1)re(j, n + 1)a[i][j] = 0;
55         */
56         while (q--){
57             char op[2]; scanf("%s", op);
58             if (op[0] == ‘Q‘){
59                 scanf("%d%d",&x,&y);
60                 ans = 0;
61                 queryx(1, 1, n);
62                 printf("%d\n", ans & 1);
63             }
64             else{
65                 scanf("%d%d%d%d", &fx, &fy, &tx, &ty);
66                 if (fx > tx)swap(fx, tx); if (fy > ty)swap(fy, ty);
67                 updatex(1,1,n);
68                 //debug();
69             }
70         }
71         if (T)puts("");
72     }
73     return 0;
74 }

zkw二维线段树 开区间写法

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn =1007;
 6 typedef long long ll;
 7 #define re(i,n) for(int i=0;i<n;i++)
 8 bool tr[maxn << 2][maxn << 2];
 9 int n, q,sz;
10 bool yquery(int x, int y){
11     y += sz;
12     bool ans = 0;
13     /*
14     因为1是哨兵节点,1必然始终都为0,不曾变化,所以算上1也无妨
15     */
16     while (y){
17         ans ^= tr[x][y];
18         y >>= 1;
19     }
20     return ans;
21 }
22 bool query(int x,int y){
23     x += sz;
24     int ans = 0;
25     while (x){
26         ans ^= yquery(x, y);
27         x >>= 1;
28     }
29     return ans;
30 }
31 void yupdate(int x, int fy, int ty){
32     fy += sz - 1, ty += sz + 1;
33     while (fy^ty ^ 1){
34         if (~fy & 1)tr[x][fy ^ 1] ^= 1;
35         if (ty & 1)tr[x][ty ^ 1] ^= 1;
36         fy >>= 1, ty >>= 1;
37     }
38 }
39 void update(int fx,int fy,int tx,int ty){
40     fx += sz - 1, tx += sz + 1;
41     while (fx^tx ^ 1){
42         if (~fx & 1)yupdate(fx^1, fy, ty);
43         if (tx & 1)yupdate(tx ^ 1, fy, ty);
44         fx >>= 1, tx >>= 1;
45     }
46 }
47 int main(){
48     //freopen("in.txt", "r", stdin);
49     int T; cin >> T;
50     while (T--){
51         scanf("%d%d", &n, &q);
52         sz = 1; while (sz < n+2)sz <<= 1;
53         memset(tr, 0, sizeof(tr));
54         while (q--){
55             char op[2]; scanf("%s", op);
56             if (op[0] == ‘Q‘){
57                 int x, y; scanf("%d%d", &x, &y);
58                 bool ans = query(x, y);
59                 printf("%d\n", ans);
60             }
61             else{
62                 int fx, fy, tx, ty; scanf("%d%d%d%d", &fx, &fy, &tx, &ty);
63                 if (fx > tx)swap(fx, tx); if (fy > ty)swap(fy, ty);
64                 update(fx, fy, tx, ty);
65             }
66         }
67         puts("");
68     }
69     return 0;
70 }

zwk二维线段树闭区间写法

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn =1007;
 6 typedef long long ll;
 7 #define re(i,n) for(int i=0;i<n;i++)
 8 bool tr[maxn << 2][maxn << 2];
 9 int n, q,sz;
10 bool yquery(int x, int y){
11     y += sz-1;
12     bool ans = 0;
13     /*
14     因为1是哨兵节点,1必然始终都为0,不曾变化,所以算上1也无妨
15     */
16     while (y){
17         ans ^= tr[x][y];
18         y >>= 1;
19     }
20     return ans;
21 }
22 bool query(int x,int y){
23     x += sz-1;
24     int ans = 0;
25     while (x){
26         ans ^= yquery(x, y);
27         x >>= 1;
28     }
29     return ans;
30 }
31 /*
32 开区间=闭区间-两个端点.
33 所以,先处理两个端点之后就变成了开区间.
34 两个端点处理时要加上一个判断,l==r,如果相等,那就不能对同一个点处理两次,只处理一个点然后返回就行了;如果不等,那就先处理两端,再按照开区间的方式进行处理.
35 */
36 void yupdate(int x, int fy, int ty){
37     fy += sz - 1, ty += sz -1;
38     if (fy == ty){ tr[x][fy] ^= 1; return; }
39     tr[x][fy] ^= 1, tr[x][ty] ^= 1;
40     while (fy^ty ^ 1){
41         if (~fy & 1)tr[x][fy ^ 1] ^= 1;
42         if (ty & 1)tr[x][ty ^ 1] ^= 1;
43         fy >>= 1, ty >>= 1;
44     }
45 }
46 void update(int fx,int fy,int tx,int ty){
47     fx += sz - 1, tx += sz - 1;
48     if (fx == tx){
49         yupdate(fx, fy, ty); return;
50     }
51     yupdate(fx, fy, ty), yupdate(tx, fy, ty);
52     while (fx^tx ^ 1){
53         if (~fx & 1)yupdate(fx^1, fy, ty);
54         if (tx & 1)yupdate(tx ^ 1, fy, ty);
55         fx >>= 1, tx >>= 1;
56     }
57 }
58 int main(){
59     freopen("in.txt", "r", stdin);
60     int T; cin >> T;
61     while (T--){
62         scanf("%d%d", &n, &q);
63         sz = 1; while (sz < n)sz <<= 1;
64         memset(tr, 0, sizeof(tr));
65         while (q--){
66             char op[2]; scanf("%s", op);
67             if (op[0] == ‘Q‘){
68                 int x, y; scanf("%d%d", &x, &y);
69                 bool ans = query(x, y);
70                 printf("%d\n", ans);
71             }
72             else{
73                 int fx, fy, tx, ty; scanf("%d%d%d%d", &fx, &fy, &tx, &ty);
74                 if (fx > tx)swap(fx, tx); if (fy > ty)swap(fy, ty);
75                 update(fx, fy, tx, ty);
76             }
77         }
78         putchar(10);//换行是10,回车13,空格32
79     }
80     return 0;
81 }
时间: 2024-10-07 21:21:51

POJ2155 Matrix二维线段树经典题的相关文章

poj2155 Matrix 二维线段树

二维线段树区间更新和单点查询,由于二维线段树不能传递标记,所以区间更新和一维不太一样,需要用到被更新的值以及更新操作的一些性质,还有要注意对query的影响. 这里操作是翻转,而且是单点查询,所以就直接在矩形块内更新,不把标记传递下去,查询的时候做一下微调,把所有经过的路径的标记都判断一遍,看是否需要翻转,这样就解决了这道题. 上一道是单点更新和区间求和,当然就不用标记了,把所有的第一维的第二层的y点全部更新,查询的时候不用查到最底层也能查到了. 二维线段树还是比较灵活,但这已经是最简单的树套树

POJ2155 Matrix二维线段树

一,题意: 给你一个全为0的N * N的矩阵,对这个矩阵有两个操作(对于矩阵只有两个状态0,1) (1):"C x1,y1,x2,y2"   就是将左上角为x1,y1,右下角为x2,y2,的这个矩阵内的数字全部翻转. (2):"Q x1 y1"   输出a[x1][y1]的值. 二,解析: 该我主要应用令二位的树状数组,一个是行,一个是列. 三,代码: #include<iostream> #include<cstdio> #include

POJ 2155 二维线段树 经典的记录所有修改再统一遍历 单点查询

本来是想找一个二维线段树涉及懒惰标记的,一看这个题,区间修改,单点查询,以为是懒惰标记,敲到一半发现这二维线段树就不适合懒惰标记,你更新了某段的某列,但其实其他段的相应列也要打标记,但因为区间不一样,又不好打...也可能是我这是在套用一维线段树的思想,还有更好的二维线段树懒惰标记方法 反正到现在我还没搞定二维线段树的懒惰标记,因为这道题不用懒惰标记,因为是二进制序列,区间修改仅限于翻转操作,那就只要记录每次操作,最后查询的时候从上往下把所有修改都来上一遍,就可以了.就类似于树状数组的第二种用法,

POJ 2155 Matrix (二维线段树)

http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 18143   Accepted: 6813 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. I

POJ 2155 Matrix 二维线段树+标记永久化?

题意:链接 方法:二维线段树+标记永久化 解析:题意是比较明朗的,算一下内存发现4000^2也是可以接受的,于是就开始yy二维线段树? 对于第一层x的线段树,每个节点开一整棵y线段树. 用个二维数组就实现了? 不过发现个问题啊,这题怎么pushdown啊,标记传不下去啊.如果给x打个标记那么怎么知道y传那段啊? 于是就学了新的东西?标记永久化. 本题是单点查询嘛,标记永久化就应该是把相应的区间直接异或,不用往下传?那查询的时候怎么办呢?只需要在查询的时候把所有路过该点的区间都异或起来就OK了.貌

poj 1195:Mobile phones(二维线段树,矩阵求和,经典题)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14391   Accepted: 6685 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

HDU 1823 二维线段树

二维线段树入门题 分别以身高和活泼度开两维 以身高-100,活泼度*10,为两个区间 所谓的二维就是在第一维查找到正确位置时,进入第二维再查找 #include "stdio.h" #include "string.h" double ans; double Max(double a,double b) { if (a<b) return b;else return a; } struct Mark { int l,r; double x; }; struct

二维线段树模版

HDU 4819 二维线段树模版题 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int INF = 999999999; const int maxn = 810; int a[maxn][maxn]; int st_min[maxn<<2][maxn<<2]; int st_max[maxn<<2][maxn

HDU 4819 Mosaic (二维线段树)

Problem Description The God of sheep decides to pixelate some pictures (i.e., change them into pictures with mosaic). Here's how he is gonna make it: for each picture, he divides the picture into n x n cells, where each cell is assigned a color value