矩阵修改(二维线段树、矩形树)
2017-03-13 20:55
316 查看
矩阵修改(二维线段树、矩形树)
题目描述
有一个n*m的矩阵(原始矩阵有值),现在可以对矩阵进行k次操作输入
开始n行,每行m个整数,表示原始矩阵后k行每行先是一个字符表示操作类型,后跟4个整数,表示范围。若是修改操作还会给出1个整数表示修改值。
操作分为三类:
A x1 y1 x2 y2 val:表示对左上角为x1,y1,右下角为x2,y2的区域加上val
S x1 y1 x2 y2 val:表示对左上角为x1,y1,右下角为x2,y2的区域减去val
Q x1 y1 x2 y2:表示查询左上角为x1,y1,右下角为x2,y2的区域的和
输出
对于每次查询,输出结果。每个结果占一行数据规模
n,m<=1000,k<=10000[b]**************[/b]华丽的分界线[b]**************[/b]
引言
其实就是一道二维线段树的裸题,但网上二维线段树的资源好像少的可怜,有的也只是树套树版本的,好像无法满足区间修改和区间查询。而且矩形树相对于树套树来说,在代码性能和写起来的难易程度上来说也要好上不少。主要是好理解,还有一维线段树的flg懒标记在矩形树上同样适用。
Code思路
先声明:这里矩形树的当做完全四叉树来做(方便计算儿子和父亲的下标)矩形树的代码其实跟一维线段树的写法差不多,只是由二叉变成了四叉而已。 首先,一个节点定义为一个结构体,成员包括:坐标信息x1,y1,x2,y2(表示该节点的区间为以(x1,y1)为左上角(x2,y2)为右下角的矩形区域)和其他含义信息比如区间和sum,懒标记flg,区间最大值max,最小值min...什么的你自己根据需要去定就行了。
结构体代码:
const int MAXN = 1000; struct node{ short x1, y1, x2, y2; int sum, flg; }T[MAXN * MAXN * 4];
至于建树操作我们可以模仿,一维线段树的建树操作在x方向和y方向二分,如果x或y方向上长度为1了,那在该方向上就不在进行二分了。如果x,y方向上长度均为一了(即x1=x2且y1=y2),就说明到了树的最底层的单位节点了就可以返回了。
建树代码:
void build(int u, short x1, short x2, short y1, short y2){ T[u].x1 = x1; T[u].x2 = x2; T[u].y1 = y1; T[u].y2 = y2; if(x1 == x2 && y1 == y2) return; short midx = (x1 + x2) >> 1; short midy = (y1 + y2) >> 1; if(x1 == x2){ build(son1, x1, x2, y1, midy); build(son3, x1, x2, midy + 1, y2); } else if(y1 == y2){ build(son1, x1, midx, y1, y2); build(son2, midx + 1, x2, y1, y2); } else{ build(son1, x1, midx, y1, midy); build(son2, midx + 1, x2, y1, midy); build(son3, x1, midx, midy + 1, y2); build(son4, midx + 1, x2, midy + 1, y2); } }
建树看懂了,这个代码就好写了,插入和查询跟一维线段树基本一样,这里就不单独写了,不懂的话就,看代码吧。
Code
#include<cstdio> #define son1 (u << 2) - 2 #define son2 (u << 2) - 1 #define son3 (u << 2) #define son4 (u << 2) | 1 const int MAXN = 1000; struct node{ short x1, x2, y1, y2; int sum, flg; }T[MAXN * MAXN * 2]; int mp[MAXN + 5][MAXN + 5]; template <class T> inline void Read(T &Ret){ char ch; int flg = 1; while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') flg = -1; Ret = ch - '0'; while(ch = getchar(), ch >= '0' && ch <= '9') Ret = Ret * 10 + ch - '0'; ungetc(ch, stdin); Ret *= flg; } inline int sq(int u){return (T[u].x2 - T[u].x1 + 1) * (T[u].y2 - T[u].y1 + 1);} inline void pushdown(int u){ if(!T[u].flg) return; if(T[son1].x1) T[son1].sum += sq(son1) * T[u].flg, T[son1].flg += T[u].flg; if(T[son2].x1) T[son2].sum += sq(son2) * T[u].flg, T[son2].flg += T[u].flg; if(T[son3].x1) T[son3].sum += sq(son3) * T[u].flg, T[son3].flg += T[u].flg; if(T[son4].x1) T[son4].sum += sq( 4000 son4) * T[u].flg, T[son4].flg += T[u].flg; T[u].flg = 0; } inline void pushup(int u){T[u].sum = T[son1].sum + T[son2].sum + T[son3].sum + T[son4].sum;} void build(int u, short x1, short x2, short y1, short y2){ T[u].x1 = x1; T[u].x2 = x2; T[u].y1 = y1; T[u].y2 = y2; if(x1 == x2 && y1 == y2){ T[u].sum = mp[x1][y1]; return; } short midx = (x1 + x2) >> 1; short midy = (y1 + y2) >> 1; if(x1 == x2) build(son1, x1, x2, y1, midy), build(son3, x1, x2, midy + 1, y2); else if(y1 == y2) build(son1, x1, midx, y1, y2), build(son2, midx + 1, x2, y1, y2); else{ build(son1, x1, midx, y1, midy); build(son2, midx + 1, x2, y1, midy); build(son3, x1, midx, midy + 1, y2); build(son4, midx + 1, x2, midy + 1, y2); } pushup(u); } void Insert(int u, short x1, short x2, short y1, short y2, int v){ if(x2 < T[u].x1 || T[u].x2 < x1) return; if(y2 < T[u].y1 || T[u].y2 < y1) return; if(x1 <= T[u].x1 && T[u].x2 <= x2 && y1 <= T[u].y1 && T[u].y2 <= y2){ T[u].sum += sq(u) * v; T[u].flg += v; return; } pushdown(u); Insert(son1, x1, x2, y1, y2, v); Insert(son2, x1, x2, y1, y2, v); Insert(son3, x1, x2, y1, y2, v); Insert(son4, x1, x2, y1, y2, v); pushup(u); } int getsum(int u, short x1, short x2, short y1, short y2){ if(x2 < T[u].x1 || T[u].x2 < x1) return 0; if(y2 < T[u].y1 || T[u].y2 < y1) return 0; if(x1 <= T[u].x1 && T[u].x2 <= x2 && y1 <= T[u].y1 && T[u].y2 <= y2) return T[u].sum; pushdown(u); int res = 0; res += getsum(son1, x1, x2, y1, y2); res += getsum(son2, x1, x2, y1, y2); res += getsum(son3, x1, x2, y1, y2); res += getsum(son4, x1, x2, y1, y2); pushup(u); return res; } int main(){ short n, m, a, b, c, d, k; int v; char id[3]; Read(n); Read(m); Read(k); for(int i = 1; i <= n; ++ i) for(int j = 1; j <= m; ++ j) Read(mp[i][j]); build(1, 1, n, 1, m); while(k --){ scanf("%s",id); Read(a); Read(b); Read(c); Read(d); switch(id[0]){ case 'A': Read(v), Insert(1, a, c, b, d, v); break; case 'S': Read(v), Insert(1, a, c, b, d, -v); break; default: printf("%d\n",getsum(1, a, c, b, d)); } } return 0; }
相关文章推荐
- 树状数组实现矩阵中矩形区域的修改以及求和
- 【POJ2155】Matrix 二维线段树点修改区间查询
- poj 1195:Mobile phones(二维线段树,矩阵求和)
- 【bzoj5173】[Jsoi2014]矩形并 扫描线+二维树状数组区间修改区间查询
- uva 1401 Fast Matrix Operations 快速矩阵操作 (线段树 区间修改和查询)
- ZOJ 3018 Population(二维线段树?矩形树?)
- tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树
- poj 2155:Matrix(二维线段树,矩阵取反,好题)
- POJ——1195Mobile phones(二维树状数组点修改矩阵查询)
- 二维线段树区域修改,最大值最小值
- POJ 2155 Matrix 二维线段树 区间修改 单点查询
- UVA-11297-Census(二维线段树RMQ,单点修改)
- Arithmetic problem | 找二维矩阵权值为1的最大矩形面积
- POJ - 2155 Matrix (二维树状数组 + 区间修改 + 单点求值 或者 二维线段树 + 区间更新 + 单点求值)
- POJ 2155 二维线段树 经典的记录所有修改再统一遍历 单点查询
- 【HDU5892 2016 ACM ICPC Asia Regional Shenyang Online A】【二维树状数组模板 区间修改】nn矩阵内子矩阵中各怪兽数量的奇偶性.cpp
- 给定填充0和1的二维二进制矩阵,找到包含所有的最大矩形并返回其区域。
- 树套树:二维线段树初步:hdu1823——Luck and Love(单点修改,区间查询)
- 【JZOJ5270】【GDOI2018模拟】神奇的矩阵(二维线段树)
- 二维线段树区间修改(add,set)uva11992