题意: 有一个n*n的矩阵,初始化全部为0。有2中操作; 1、给一个子矩阵,将这个子矩阵里面所有的0变成1,1变成0;2、询问某点的值

方法一:二维线段树

参考链接:

http://blog.csdn.net/xiamiwage/article/details/8030273

思路: 二维线段树,一维线段树的成段更新需要lazy。 引申到二维线段树应该需要一个lazy,一个sublazy,可是这里什么都不用。

     奇妙之处在于这题的操作是异或,当某一段区间需要异或操作时候, 不必更新到它所有的叶子结点,可以像lazy那样父结点异或后就返回。

   只要在查询时从根节点开始异或,而不是直接查叶子结点,这样相当于将lazy储存在父结点上。

#include <iostream>
#include <stdio.h>
#include <string.h> using namespace std;
const int maxn=;
int tree[maxn*][maxn*];
int n,t,sum;
/*
更新子线段树,tl、tr对应子矩阵的y1、y2,即要更新的范围。
rtx:母线段树(x轴)的节点,表示该子线段树属于母线段树的节点rtx
rt:子线段树的节点序号
L,R为子线段树节点rt的两端点
*/
void updatey(int rtx,int rt,int tl,int tr,int L,int R){
//一开始弄反了,写成L<=tl && tr<=R。。。
//要注意,应该是所在节点rt的区间在所要更新的节点范围里,更新节点rt的区间对应的值
if(tl<=L && R<=tr){
tree[rtx][rt]^=; //对属于更新范围里的子矩阵进行取反
return;
}
int mid=(L+R)>>;
//下面部分也可以换成注释掉的语句
if(tl<=mid)
updatey(rtx,rt<<,tl,tr,L,mid);
if(tr>mid)
updatey(rtx,rt<<|,tl,tr,mid+,R);
/*
if(tr<=mid)
updatey(rtx,rt<<1,tl,tr,L,mid);
else if(tl>mid)
updatey(rtx,rt<<1|1,tl,tr,mid+1,R);
else{
updatey(rtx,rt<<1,tl,mid,L,mid);
updatey(rtx,rt<<1|1,mid+1,tr,mid+1,R);
}
*/ }
/*
更新左上角(x1,y1),右下角(xr,yr)的子矩阵区域
更新时,先在x轴找到对应[xl,xr]区间的点,再找按y轴找到对应[yl,yr]区间的节点
rt:母线段树的节点序号
L,R:rt节点的区间端点
*/
void updatex(int rt,int xl,int xr,int yl,int yr,int L,int R){
//一开始弄反了,写成L<=xl && xr<=R。。。
if(xl<=L && R<=xr){
updatey(rt,,yl,yr,,n);
return;
}
int mid=(L+R)>>;
//下面部分也可以换成注释掉的语句
if(xl<=mid)
updatex(rt<<,xl,xr,yl,yr,L,mid);
if(xr>mid)
updatex(rt<<|,xl,xr,yl,yr,mid+,R);
/*
if(xr<=mid)
updatex(rt<<1,xl,xr,yl,yr,L,mid);
else if(xl>mid)
updatex(rt<<1|1,xl,xr,yl,yr,mid+1,R);
else{
updatex(rt<<1,xl,mid,yl,yr,L,mid);
updatex(rt<<1|1,mid+1,xr,yl,yr,mid+1,R);
}
*/ }
/*
这里注意的是,是直到L!=R的时候,才停止查询,否则就要一直查询下去,直到查询到y所在的叶子节点
因为这里“异或”就相当于lazy标记,所以要获得最后的值,则必须遍历过y所在的所有子矩阵
rtx:母线段树(x轴)的节点,表示该子线段树属于母线段树的节点rtx
rt:子线段树的节点序号
L,R为子线段树节点rt的两端点
*/
void queryy(int rtx,int rt,int y,int L,int R){
sum^=tree[rtx][rt]; //这里注意:要先异或!
if(L!=R){
int mid=(L+R)>>;
if(y<=mid)
queryy(rtx,rt<<,y,L,mid);
else
queryy(rtx,rt<<|,y,mid+,R);
}
}
/*
这里注意的是,是直到L!=R的时候,才停止查询,否则就要一直查询下去,直到查询到点x所在的叶子节点
因为这里“异或”就相当于lazy标记,所以要获得(x,y)最后的值,则必须遍历过(x,y)点所在的所有子矩阵
rt:母线段树的节点序号
L,R为子线段树节点rt的两端点
x,y为所要查找的点的值
*/
void queryx(int rt,int x,int y,int L,int R){
queryy(rt,,y,,n);
//注意:当L<R的时候,还要继续往下查询,直到L=R=y。而不是到L<=Y<=R的时候就停止
if(L!=R){
int mid=(L+R)>>;
if(x<=mid)
queryx(rt<<,x,y,L,mid);
else
queryx(rt<<|,x,y,mid+,R);
}
}
int main()
{
int x,x1,x2,y1,y2;
char s[];
scanf("%d",&x);
while(x--){
memset(tree,,sizeof(tree));
scanf("%d%d",&n,&t);
for(int i=;i<=t;i++){
scanf("%s",s);
if(s[]=='C'){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
updatex(,x1,x2,y1,y2,,n);
}
else{
sum=; //查询的A(x,y)的值
scanf("%d%d",&x1,&y1);
queryx(,x1,y1,,n);
printf("%d\n",sum);
}
}
puts(" ");
}
return ;
}

方法二:二维树状数组

区间更新,单点查询
(修改一个区间的值,快速返回某一点处的值。)

树状数组有两种用途(以一维树状数组举例):
  1.单点更新,区间查询(即求和)
    单点更新时,是往树根(即c[n])拓展
    而区间查询时,是往叶子节点(即c[1])拓展
  2.区间更新,单点查询
    区间更新时,是往叶子节点(即c[1])拓展
    单点查询时,往树根(即c[n])拓展

二维数组就是多了一层循环,其余一致

具体实现:
  更新的时候,要更新四个矩阵,见下图,我采用的是法二。

  每次查询时,统计该点被取反的次数,然后模2即为答案。

图片来自:http://blog.csdn.net/zxy_snow/article/details/6264135

    即如果要对矩阵D中的元素取反,那么我先对ABCD四个矩阵操作一次(+1),再对矩阵AC和BC操作一次(-1),然后还要对矩阵C操作一次(+1)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm> using namespace std;
const int maxn=;
int c[maxn][maxn];
int x,n,t; int lowbit(int x){
return x&(-x);
}
/*
原先一直WA,是因为直接用参数的i和j参与循环了
后来定义了变量x和y,就AC了。。。
后来仔细发现,每当外循环一次时,内循环就要从头开始。
而如果我直接用参数j参与循环,那么只有第一次外循环时,内循环执行。之后的外循环,内循环就再也不执行了。
真的是囧啊!!!
*/
void update(int i,int j,int v){
for(int x=i;x>=;x-=lowbit(x)){
for(int y=j;y>=;y-=lowbit(y))
c[x][y]+=v;
}
}
int sum(int i,int j){
int res=;
for(int x=i;x<=n;x+=lowbit(x)){
for(int y=j;y<=n;y+=lowbit(y))
res+=c[x][y];
}
return res;
}
int main()
{
char str[];
int x1,y1,x2,y2;
scanf("%d",&x);
bool flag=false;
while(x--){ if(flag)
puts("");
else
flag=true; scanf("%d%d",&n,&t);
memset(c,,sizeof(c));
while(t--){
scanf("%s",str);
if(str[]=='C'){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
update(x2,y2,); //矩阵ABCD
update(x1-,y2,-); //矩阵AC
update(x2,y1-,-); //矩阵BC
update(x1-,y1-,); //矩阵C
}
else{
scanf("%d%d",&x1,&y1);
int ans=sum(x1,y1);
if(ans%==)
printf("0\n");
else
printf("1\n");
}
}
}
return ;
}

POJ 2155 Matrix (二维线段树入门,成段更新,单点查询 / 二维树状数组,区间更新,单点查询)的更多相关文章

  1. 【poj2155】Matrix(二维树状数组区间更新+单点查询)

    Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the ...

  2. 牛客网 暑期ACM多校训练营(第二场)J.farm-STL(vector)+二维树状数组区间更新、单点查询 or 大暴力?

    开心.jpg J.farm 先解释一下题意,题意就是一个n*m的矩形区域,每个点代表一个植物,然后不同的植物对应不同的适合的肥料k,如果植物被撒上不适合的肥料就会死掉.然后题目将每个点适合的肥料种类( ...

  3. HDU 3333 Turing Tree 离线 线段树/树状数组 区间求和单点修改

    题意: 给一个数列,一些询问,问你$[l,r]$之间不同的数字之和 题解: 11年多校的题,现在属于"人尽皆知傻逼题" 核心思想在于: 对于一个询问$[x,R]$ 无论$x$是什么 ...

  4. POJ 2155 Matrix(二维树状数组+区间更新单点求和)

    题意:给你一个n*n的全0矩阵,每次有两个操作: C x1 y1 x2 y2:将(x1,y1)到(x2,y2)的矩阵全部值求反 Q x y:求出(x,y)位置的值 树状数组标准是求单点更新区间求和,但 ...

  5. POJ2155 Matrix(二维树状数组||区间修改单点查询)

    Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row an ...

  6. poj2155二维树状数组区间更新

    垃圾poj又交不上题了,也不知道自己写的对不对 /* 给定一个矩阵,初始化为0:两种操作 第一种把一块子矩阵里的值翻转:0->1,1->0 第二种询问某个单元的值 直接累计单元格被覆盖的次 ...

  7. POJ 3468 A Simple Problem with Integers(树状数组区间更新)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 97217   ...

  8. poj 3468: A Simple Problem with Integers (树状数组区间更新)

    题目链接: http://poj.org/problem?id=3468 题目是对一个数组,支持两种操作 操作C:对下标从a到b的每个元素,值增加c: 操作Q:对求下标从a到b的元素值之和. 这道题也 ...

  9. HDU 4031 Attack(线段树/树状数组区间更新单点查询+暴力)

    Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Sub ...

  10. NBOJv2 1050 Just Go(线段树/树状数组区间更新单点查询)

    Problem 1050: Just Go Time Limits:  3000 MS   Memory Limits:  65536 KB 64-bit interger IO format:  % ...

随机推荐

  1. ueditor插件简单使用

    下载地址:http://ueditor.baidu.com/website/download.html 建议同时下载所需版本及完整源码.   [ 1.4.3 JSP + 完整源码src ] 简单配置说 ...

  2. Linux查看操作系统时间

    date命令的功能是显示和设置系统日期和时间. 该命令的一般格式为: date [选项] 显示时间格式(以+开头,后面接格式) date 设置时间格式 命令中各选项的含义分别为: -d datestr ...

  3. XAML-1

    1.XAML Extension Application Marked Language,是WPF技术中专门用来设计UI的语言.XAML是从XML派生出来的,是一种声明式语言,当你看到一个标签,就是声 ...

  4. Android Studio开发环境部署

    Step0:背景,那些年-- Step1:安装JDK Step2:安装Android Studio 其他问题1:安装Android Studio之前没有先安装JDK 其他问题2:No JVM inst ...

  5. scanf与gets函数混用 前后位置出错的问题解决

    scanf与gets函数混用 利用scanf函数从键盘接收一字符(或整数)时,它只读入字符(或整数)本身,而把字符(或整数)后的回车符留在输入缓冲区内:gets函数从标准的输入读取,如果使用gets函 ...

  6. validate 表单验证

    转自博客园:http://www.cnblogs.com/easyinsc/archive/2009/02/27/1407826.html (1)required:true               ...

  7. poj 2586 Y2K Accounting Bug (贪心)

    Y2K Accounting Bug Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8678   Accepted: 428 ...

  8. 深入理解ES6之—增强的数组功能

    创建数组 Array.of()方法 ES6为数组新增创建方法的目的之一,是帮助开发者在使用Array构造器时避开js语言的一个怪异点.Array.of()方法总会创建一个包含所有传入参数的数组,而不管 ...

  9. PPPOE拨号上网流程及密码窃取具体实现

    楼主学生党一枚,最近研究netkeeper有些许心得. 关于netkeeper是调用windows的rasdial来进行上网的东西,网上已经有一大堆,我就不赘述了. 本文主要讲解rasdial的部分核 ...

  10. webService之helloword(java)

    webservice 远程数据交互技术 1.导入jar包(如果是 maven项目导入项目坐标) 2.创建服务 3.测试服务 我们使用maven来做测试服务 pom.xml文件 <project ...