您的位置:首页 > 其它

矩阵修改(二维线段树、矩形树)

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐