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
", 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
", 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
", 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
", 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 }
原文地址:https://www.cnblogs.com/weiyinfu/p/4855589.html