poj 2155 二维线段树
在一个二维数组中,每次对一个矩形内所有数据进行取反操作,并实时询问某一位置的值。
一般线段树只支持对一维数据进行更新和查询,但是这题给的是二维数据啊!
这里就需要用到二维线段树了,即树套树,外层线段树的每个结点里面都有一颗线段树。
在实现二维线段树的时候,一开始用加build函数的方式,记录每个结点左右孩子的编号,但超内存了,所以直接用二维数组表示二维线段树,左右孩子编号通过计算得到:设父亲结点为O,左孩子结点就是O*2,右孩子结点就是O*2+1。
这样既省去了建树的时间,也省去了存储左右孩子编号的空间。但是要注意的是这时候数组要开到MAXN*4,而平时只需要开到MAXN*2,因为这里的计算左右孩子结点的方法无疑是浪费了一些空间的。
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; const int MAXN = 1002; int n; bool tree[MAXN*4][MAXN*4]; void updy(bool *tree,int cur,int curl,int curr,int l,int r){ if(curl==l&&curr==r) { tree[cur] = !tree[cur]; return; } int mid = (curl+curr)>>1; if(l>=mid+1) updy(tree,cur*2+1,mid+1,curr,l,r); else if(r<=mid) updy(tree,cur*2,curl,mid,l,r); else { updy(tree,cur*2+1,mid+1,curr,mid+1,r); updy(tree,cur*2,curl,mid,l,mid); } } void upd(int cur,int curl,int curr,int l,int r,int y1,int y2){ if(curl==l&&curr==r) { updy(tree[cur],1,1,n,y1,y2); return; } int mid = (curl+curr)>>1; if(l>=mid+1) upd(cur*2+1,mid+1,curr,l,r,y1,y2); else if(r<=mid) upd(cur*2,curl,mid,l,r,y1,y2); else { upd(cur*2+1,mid+1,curr,mid+1,r,y1,y2); upd(cur*2,curl,mid,l,mid,y1,y2); } } bool queryy(bool *tree,int cur,int curl,int curr,int l){ if(curl==curr) { return tree[cur]; } int mid = (curl+curr)>>1; if(l>=mid+1) return tree[cur]^queryy(tree,cur*2+1,mid+1,curr,l); else if(l<=mid) return tree[cur]^queryy(tree,cur*2,curl,mid,l); } bool query(int cur,int curl,int curr,int l,int r){ if(curl==curr) { return queryy(tree[cur],1,1,n,r); } int mid = (curl+curr)>>1; if(l>=mid+1) return queryy(tree[cur],1,1,n,r)^query(cur*2+1,mid+1,curr,l,r); else if(l<=mid) return queryy(tree[cur],1,1,n,r)^query(cur*2,curl,mid,l,r); } int main() { int T,X,lx,ly,rx,ry; scanf("%d",&X); char op[10]; while(X--&&scanf("%d%d",&n,&T)!=EOF) { memset(tree,0,sizeof(tree)); while(T--) { scanf("%s",op); if(op[0]=='C') { scanf("%d%d%d%d",&lx,&ly,&rx,&ry); upd(1,1,n,lx,rx,ly,ry); } else { scanf("%d%d",&lx,&ly); printf("%d\n",query(1,1,n,lx,ly)); } } puts(""); } }