zoukankan      html  css  js  c++  java
  • POJ 2155 Matrix【二维树状数组+YY(区间计数)】

    题目链接:http://poj.org/problem?id=2155

    Matrix

    Time Limit: 3000MS   Memory Limit: 65536K
    Total Submissions: 32950   Accepted: 11943

    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]. 

    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. 

    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. 

    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
    

    Source

    POJ Monthly,Lou Tiancheng

    题意概括:

    有一个初始值为0的N*N的二维矩阵,有T次操作,每次操作有两种选择:

    C : 修改以(x1, y1)为左上角(x2, y2)为右下角的矩阵的值(0和1互换)

    Q:查询(x, y)的值为 0 或者 为 1;

    解题思路:

    涉及到多次区间修改和区间查询的优先考虑线段树和树状数组,这道题巧妙之处在于灵活运用树状数组的前缀和,把区间修改转换单点修改,一维需要标记两个点而二维需要标记四个点,一个点用于发挥效果,另外三个点用于消除效果,因为树状数组维护的是前缀和,而对于二维树状数组,查询的则是以(1,1)为左上角,(x,y)为右下角的矩阵的和。

    第二就是我们可以借助修改次数的奇偶性来判断该点的值为 0 / 1;

    例如:N = 3;C:x1 = 1, y1 = 1, x2 = 2, y2 = 2; 

    1   1
      (x,y)  
    1   1

    (因为我们只需要知道奇偶性,所以矩阵外的点加1即可消除效果)

    AC code:

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 #define ll long long int;
     7 #define INF 0x3f3f3f3f
     8 using namespace std;
     9 const int MAXN = 1e3+10;
    10 
    11 int mmp[MAXN][MAXN];
    12 int N, T;
    13 
    14 int lowbit(int x)
    15 {
    16     return x&(-x);
    17 }
    18 
    19 void add(int x, int y, int value)
    20 {
    21     for(int i = x; i <= N; i += lowbit(i))
    22     for(int j = y; j <= N; j += lowbit(j))
    23         mmp[i][j]+=value;
    24 }
    25 
    26 int sum(int x, int y)
    27 {
    28     int res = 0;
    29     for(int i = x; i > 0; i -= lowbit(i))
    30     for(int j = y; j > 0; j -= lowbit(j))
    31         res+=mmp[i][j];
    32     return res;
    33 }
    34 
    35 void init()
    36 {
    37     for(int i = 0; i <= N; i++)
    38         for(int j = 0; j <= N; j++)
    39         mmp[i][j] = 0;
    40 }
    41 
    42 int main()
    43 {
    44     int T_case;
    45     char com[3];
    46     int x, y, x1, x2, y1, y2;
    47     scanf("%d", &T_case);
    48     while(T_case--)
    49     {
    50         scanf("%d%d", &N, &T);
    51         init();
    52         while(T--)
    53         {
    54             scanf("%s", &com);
    55             if(com[0] == 'C')
    56             {
    57                 scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    58                 add(x1, y1, 1);
    59                 add(x2+1, y1, 1);
    60                 add(x1, y2+1, 1);
    61                 add(x2+1, y2+1, 1);
    62             }
    63             else if(com[0] == 'Q')
    64             {
    65                 scanf("%d%d", &x, &y);
    66                 int res = 0;
    67                 res = sum(x, y);
    68                // printf("res: %d
    ", res);
    69                 if(res%2) printf("1
    ");
    70                 else printf("0
    ");
    71             }
    72         }
    73         puts("");
    74     }
    75     return 0;
    76 }
    View Code
  • 相关阅读:
    Got05
    Git07
    Git09
    Git11
    Git10
    Git13
    Git12
    Git14
    Listview点击跳转页面
    《三个和尚》观后感
  • 原文地址:https://www.cnblogs.com/ymzjj/p/9465282.html
Copyright © 2011-2022 走看看