POJ - 2155 Matrix (二维树状数组 + 区间改动 + 单点求值 或者 二维线段树 + 区间更新 + 单点求值)

POJ - 2155

Matrix

Time Limit: 3000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u

Submit Status

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
题目意思是给你一个矩阵,最開始都是为0,然后给你一个左上角的坐标,右下角的坐标,将这个区域的0 -> 1,1 -> 0,然后给你一个点让你求出他此时的结果是1还是0.
这里能够用树状数组的区间改动以及单点求值。仅仅是这里是二维的树状数组,原理是一样的。

将其改变的话,能够如此,如果最開始[1....x2][1....y2]为偶数的话(这里就是看成是前辍和)
先将[1....x2][1....y2]添加1,变为奇数,然后将[1...x1 - 1][y2]添加1变为偶数,将[1....x2][y1]添加1变为偶数,而他们中间重叠的[1....x1 - 1][1....x2 - 1]部分则是被改变了三次。还是奇数,所以还有加1。将他变为偶数,如此除了[x1....x2][y1....y2]变了外。其它的地方依然没有改变。
/*
Author: 2486
Memory: 4304 KB		Time: 547 MS
Language: G++		Result: Accepted
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1000 + 5;
int C[MAXN][MAXN];
int N, X, M, x, y, x1, x2, y1, y2;
char op[10];
int lowbits(int x){
    return x & (-x);
}

void add(int x,int y){
    for(int i = x; i <= N;i += lowbits(i)){
        for(int j = y;j <= N;j += lowbits(j)){
            C[i][j] ++;
        }
    }
}

int query(int x,int y){
    int ret = 0;
    for(int i = x;i > 0;i -= lowbits(i)){
        for(int j = y;j > 0;j -= lowbits(j)){
            ret += C[i][j];
        }
    }
    return ret;
}

int main(){
    //freopen("D://imput.txt","r",stdin);
    scanf("%d", &X);
    while(X --){
        memset(C, 0, sizeof(C));
        scanf("%d%d", &N, &M);
        while(M --){
            scanf("%s", op);
            if(op[0] == ‘C‘){
                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
                x2 ++;
                y2 ++;
                add(x1, y1);
                add(x1, y2);
                add(x2, y1);
                add(x2, y2);
            }
            else{
                scanf("%d%d", &x, &y);
                printf("%d\n", query(x,y) & 1);//求和即代表求点
            }
        }
        if(X)printf("\n");
    }
    return 0;
}


线段树代码:
/*
Author: 2486
Memory: 63688 KB		Time: 1579 MS
Language: G++		Result: Accepted
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define root 1, 1, N
const int MAXN = 1000 + 5;
int N, T, CASE, x1, y1, x2, y2, ret, x, y;
char op[5];
int sum[MAXN << 2][MAXN << 2];

void update_r(int cr, int y1, int y2, int rt, int l, int r) {
    if(y1 <= l && r <= y2) {
        sum[cr][rt] = !sum[cr][rt];
        return ;
    }
    int mid = (l + r) >> 1;
    if(y1 <= mid) update_r(cr, y1, y2, lson);
    if(y2 > mid) update_r(cr, y1, y2, rson);
}

void update_c(int x1, int y1, int x2, int y2, int rt, int l, int r) {
    if(x1 <= l && r <= x2) {
        update_r(rt, y1, y2, root);
        return;
    }
    int mid = (l + r) >> 1;
    if(x1 <= mid) update_c(x1, y1, x2, y2, lson);
    if(x2 > mid) update_c(x1, y1, x2, y2, rson);
}
void query_r(int cr, int y1, int y2, int rt, int l, int r) {
    if(sum[cr][rt]) ret ++;
    if(y1 <= l && r <= y2) {
        return ;
    }
    int mid = (l + r) >> 1;
    if(y1 <= mid) query_r(cr, y1, y2, lson);
    if(y2 > mid) query_r(cr, y1, y2, rson);
}

void query_c(int x1, int y1, int x2, int y2, int rt, int l, int r) {
    query_r(rt, y1, y2, root);//选择覆盖了子树的个数
    if(x1 <= l && r <= x2) {
        return;
    }
    int mid = (l + r) >> 1;
    if(x1 <= mid) query_c(x1, y1, x2, y2, lson);
    if(x2 > mid) query_c(x1, y1, x2, y2, rson);
}

int main() {
    //freopen("D://imput.txt","r",stdin);
    scanf("%d", &CASE);
    while(CASE --) {
        memset(sum, 0, sizeof(sum));
        scanf("%d%d", &N, &T);
        while(T --) {
            scanf("%s", op);
            if(op[0] == ‘C‘) {
                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
                update_c(x1, y1, x2, y2, root);
            } else {
                scanf("%d%d", &x, &y);
                ret = 0;
                query_c(x, y, x, y, root);
                printf("%d\n", ret & 1);
            }
        }
        if(CASE)printf("\n");
    }
    return 0;
}
时间: 2024-12-26 15:56:44

POJ - 2155 Matrix (二维树状数组 + 区间改动 + 单点求值 或者 二维线段树 + 区间更新 + 单点求值)的相关文章

二维树状数组(水题) POJ1195

前段时间遇到线段树过不了,树状数组却过了的题.(其实线段树过得了的) 回忆了下树状数组. 主要原理,还是二进制位数,每一项的和表示其为它的前((最后一位1及其后)的二进制数)和,可从二进制图来看.(用线段树想一想其实只是线段树编号不同而已,本质类似) 写了下二维树状数组,几乎和一维相同,也没必要不同. #include <cstdio> #include <cstring> int l,r,x,y,n,a,p,sum[1125][1125]; inline int lowbit(i

树状数组与线段树

一:树状数组 树状数组是对一个数组改变某个元素和求和比较实用的数据结构.两中操作都是O(logn). 需求:有时候我们需要频繁地求数组的前k项和或者求数组从小标i到j的和,这样每次最坏情况下的时间复杂度就会为O(N),这样效率太低了.而树状数组主要就是为了解决这样一个问题.树状数组在求和及修改都可以在O(lgN)时间内完成. 树状数组需要额外维护一个数组,我们设为C[N],原数组为A[N], 其中每个元素C[i]表示A[i-2^k+1]到A[i]的和,这里k是i在二进制时末尾0的个数.注意通过位

HDU 1166 敌兵布阵 (线段树 &amp; 树状数组)

敌兵布阵 Time Limit:1000MS    Memory Limit:32768KB    64bit IO Format:%I64d & %I64u SubmitStatus 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的

Lightoj 1112 - Curious Robin Hood 【单点改动 + 单点、 区间查询】【树状数组 水题】

1112 - Curious Robin Hood PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another trick.

算法基础-树状数组

今天我们分享一下树状数组,前置知识-了解树的结构,知道什么是左右儿子,各个节点的名称,也就是有点基础吧.今天以一个实际问题引出树状数组吧,中查询l-r的区间.(以B站大佬的课件为例子,可以关注下,在最后放上链接) 如果是暴力的话,显然时间复杂度是接受不了的(o(n方)),为了解决这个问题,我们就要用一些高级的数据结构.就是我们今天介绍的树状数组. 首先看下树状数组是什么, 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log

hdu 1166:敌兵布阵(树状数组,练习题)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 37773    Accepted Submission(s): 15923 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就

Bestcoder7(1004)hdu4988(经典问题:树状数组套treap求解动态逆序对)

Little Pony and Boast Busters Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 83    Accepted Submission(s): 32 Problem Description "I hereby challenge you, Ponyvillians: anything you can do

【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】

模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: -------------------------------------------------------------------------------- [ 3 ]  上面都不是重点--重点是树状数组的区间修改+区间查询 这个很好玩 其实也挺简单 首先依旧是引入delta数组 delta[i]表示区间 [i, n] 的共同增量 于是修改区间 [l, r] 时修改 delt

树状数组入门 hdu1541 Stars

树状数组 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构.主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值:经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询). 树状数组和线段树很像,但能用树状数组解决的问题,基本上都能用线段树解决,而线段树能解决的树状数组不一定能解决.相比较而言,树状数组效率要

POJ-1195 Mobile phones---裸的二维树状数组(注意下标从1,1开始)

题目链接: https://vjudge.net/problem/POJ-1195 题目大意: 直接维护二维树状数组 注意横纵坐标全部需要加1,因为树状数组从(1,1)开始 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<string> 6 #include<cmath> 7 #include<