poj2155 二维线段树
来源:互联网 发布:md5加密 java验证 编辑:程序博客网 时间:2024/04/24 15:07
http://poj.org/problem?id=2155
题目大意:给定初始N*N矩阵,所有数都是0,然后有‘C’操作:对左上角(x1,y1)到右下角(x2,y2)的矩阵中所有数取非,即0变1,或1变0;还有‘Q’操作:查询点(x,y)的值并输出。
思路:构造一个线段树,每个结点还是线段树,外围线段树表示x方向,子线段树表示y方向。查询时对结点(x,y)所在的所有矩阵的值累计,这是因为在更新时,只更新到给定的矩阵(x1,x2,y1,y2),而对于这个矩阵中的点(x,y)则没有更新,而算法中没有懒操作,故查询时需将线段树中经过的每个矩阵都进行计算,以达到懒操作的功能。
代码如下:
#include <iostream>#include <cstdio>#include <memory.h>#include <algorithm>#include <cmath>#include <string>#include <climits>using namespace std;#define lson rt<<1#define rson rt<<1|1#define N 1005struct snode{ int ly,ry; bool num;};struct node{ int lx,rx; snode sst[4*N];}st[4*N];int ans;void build_sub(snode sst[],int rt,int ly,int ry){ sst[rt].ly=ly; sst[rt].ry=ry; sst[rt].num=0; if (ly==ry) return; int mid=(ly+ry)>>1; build_sub(sst,lson,ly,mid); build_sub(sst,rson,mid+1,ry);}void build(int rt,int lx,int rx,int ly,int ry){ st[rt].lx=lx; st[rt].rx=rx; build_sub(st[rt].sst,1,ly,ry); if (lx==rx) return; int mid=(lx+rx)>>1; build(lson,lx,mid,ly,ry); build(rson,mid+1,rx,ly,ry);}void update_sub(snode sst[],int rt,int y1,int y2){ if (y1<=sst[rt].ly && sst[rt].ry<=y2) { sst[rt].num^=1; return; } int mid=(sst[rt].ly+sst[rt].ry)>>1; if (y1<=mid) update_sub(sst,lson,y1,y2); if (y2>mid) update_sub(sst,rson,y1,y2);}void update(int rt,int x1,int y1,int x2,int y2){ if (x1<=st[rt].lx && st[rt].rx<=x2) { update_sub(st[rt].sst,1,y1,y2); return; } int mid=(st[rt].lx+st[rt].rx)>>1; if (x1<=mid) update(lson,x1,y1,x2,y2); if (x2>mid) update(rson,x1,y1,x2,y2);}void query_sub(snode sst[],int rt,int y){ ans^=sst[rt].num; if (y<=sst[rt].ly && sst[rt].ry<=y) return ; int mid=(sst[rt].ly+sst[rt].ry)>>1; if (y<=mid) query_sub(sst,lson,y); else query_sub(sst,rson,y);}void query(int rt,int x,int y){ query_sub(st[rt].sst,1,y); if (x<=st[rt].lx && st[rt].rx<=x) return; int mid=(st[rt].lx+st[rt].rx)>>1; if (x<=mid) query(lson,x,y); else query(rson,x,y);}int main(){ int t,n,m,x1,x2,y1,y2; char ch[10]; while(scanf("%d",&t)!=EOF) { while (t--) { scanf("%d%d",&n,&m); build(1,1,n,1,n); //puts("built"); while (m--) { scanf("%s",ch); if (ch[0]=='C') { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); update(1,x1,y1,x2,y2); } else { ans=0; scanf("%d%d",&x1,&y1); query(1,x1,y1); printf("%d\n",ans); } } printf("\n"); } } return 0;}
另外有一种二维树状数组的实现方式,比较容易写,也容易理解些。
如果是在一维的树状数组,在[L,R]的区间内进行翻转操作后,我们把C[L]++;C[R+1]- -,这样每一个sum[x]记录的就是这个点所进行翻转的次数,次数为
奇数是该点值为1,次数为偶数时该点值为0。
同理可以扩展到二维的树状数组中
代码如下
#include <iostream>#include <cstdio>#include <string>#include <memory.h>using namespace std;const int M = 1005;int c[M][M];int lowbit(int x){return x & (-x);}void init();void sol(int t);void change(int x,int y,int d);int sum(int x,int y);int result(int x,int y,int a,int b);int main(){int t;scanf("%d",&t);while(t--){int n,ci;scanf("%d%d",&c,&ci);init();sol(ci);printf("\n");}return 0;}void init(){memset(c,0,sizeof(c));return;}void sol(int t){char op[5];int x,y,a,b;while(t--){scanf("%s",&op);if(op[0] == 'C'){scanf("%d%d%d%d",&x,&y,&a,&b);intd = 1;a++;b++;change(x,y,d);change(x,b,d);change(a,y,d);change(a,b,d);}else{x = y = 0;scanf("%d%d",&a,&b);printf("%d\n",result(x,y,a,b)&1);}}return;}void change(int x,int y,int d){int i,j;for(i = x;i < M;i+=lowbit(i))for(j = y;j < M;j+=lowbit(j))c[i][j] += d;}int sum(int x,int y){int i,j,r = 0;for(i = x;i > 0;i -=lowbit(i))for(j = y;j > 0;j -= lowbit(j))r += c[i][j];return r;}int result(int x,int y,int a,int b){return sum(a,b) - sum(a,y) - sum(x,b) + sum(x,y);}
- poj2155 二维线段树
- POJ2155 二维线段树
- poj2155 二维线段树
- POJ2155二维线段树
- poj2155二维线段树
- 二维线段树 poj2155 Matrix
- POJ2155 Matrix二维线段树
- POJ2155 Matrix(二维线段树)
- poj2155-二维线段树(树套树)
- poj2155二维线段树,二维树状数组
- 二维线段树+标记永久化 poj2155
- poj2155 Matrix(二维线段树)
- poj2155 二维线段树 区间修改
- 二维线段树(二维树状数组)poj2155
- 【POJ2155】Matrix 二维线段树点修改区间查询
- poj2155 二维树状数组 二位线段树 灵活运用 待补完
- 2017sdut省赛选拔(1)--poj2155(二维线段树的翻转)
- 【线段树套线段树】POJ2155 Matrix
- oracle数据库导入导出命令
- 在android4.0.4的SDK里裁剪APK,把不需要的APK去除掉
- Android消息推送
- 第一天——寄宿家庭
- android TimerTask 动态设置时间
- poj2155 二维线段树
- Android软件开发之发送短信与系统短信库解析(三十)
- .net调用DLL
- 如何设计高效的聊天过滤词算法?
- CListCtrl使用技巧
- clang 3.1 stddef.h:61 error
- Hibernate One-to-Many using Annotations
- java 求两个数相除的值,有余数就进一位
- django分页处理