题意: 有一个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=1005; int tree[maxn*4][maxn*4]; 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]^=1; //对属于更新范围里的子矩阵进行取反 return; } int mid=(L+R)>>1; //下面部分也可以换成注释掉的语句 if(tl<=mid) updatey(rtx,rt<<1,tl,tr,L,mid); if(tr>mid) updatey(rtx,rt<<1|1,tl,tr,mid+1,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,1,yl,yr,1,n); return; } int mid=(L+R)>>1; //下面部分也可以换成注释掉的语句 if(xl<=mid) updatex(rt<<1,xl,xr,yl,yr,L,mid); if(xr>mid) updatex(rt<<1|1,xl,xr,yl,yr,mid+1,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)>>1; if(y<=mid) queryy(rtx,rt<<1,y,L,mid); else queryy(rtx,rt<<1|1,y,mid+1,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,1,y,1,n); //注意:当L<R的时候,还要继续往下查询,直到L=R=y。而不是到L<=Y<=R的时候就停止 if(L!=R){ int mid=(L+R)>>1; if(x<=mid) queryx(rt<<1,x,y,L,mid); else queryx(rt<<1|1,x,y,mid+1,R); } } int main() { int x,x1,x2,y1,y2; char s[5]; scanf("%d",&x); while(x--){ memset(tree,0,sizeof(tree)); scanf("%d%d",&n,&t); for(int i=1;i<=t;i++){ scanf("%s",s); if(s[0]=='C'){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); updatex(1,x1,x2,y1,y2,1,n); } else{ sum=0; //查询的A(x,y)的值 scanf("%d%d",&x1,&y1); queryx(1,x1,y1,1,n); printf("%d\n",sum); } } puts(" "); } return 0; }