题意
有一个r行c列的全0矩阵,支持以下3种操作,如表所示。
操作 | 备注 |
---|---|
1 x1 y1 x2 y2 v | 子矩阵(x1,y1,2,y2)的所有元素增加v(v>0) |
2 x1 y1 x2 y2 v | 子矩阵(x1,y1,x2,y2)的所有元素设为v(v>0) |
3 x1 y1 x2 y2 | 查询子矩阵(x1,y1,x2,y2)的元素和、最小值和最大值 |
子矩阵(x1,y1,x2,y2)是指满足 x 1 ≤ x ≤ x 2 , y 1 ≤ y ≤ y 2 x_1\leq x \leq x_2, y_1 \leq y \leq y_2 x1≤x≤x2,y1≤y≤y2的所有元素(x,y)。所有元素和不超过 1 0 9 10^9 109。矩阵不超过20行,元素个数不超过 1 0 6 10^6 106。
题解
由于元素个数不超过20个,所以可以把二维矩阵压成一维。在一维结构上进行线段树的操作。这里主要有set和add操作,要注意的是pushdown的时候set操作要在add之前。set操作之后要把add的标记清零。
具体代码
/*************************************************************************
> File Name: Uva11992.cpp
> Author: KyrieL
> Mail: 443999592@qq.com
> Created Time: 二 1/15 14:15:02 2019
************************************************************************/
#include <bits/stdc++.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1, r, rt<<1|1
const int maxn = 1e6+100;
int setv[maxn<<2], addv[maxn<<2],r,c,m, sumv[maxn<<2], minv[maxn<<2],maxv[maxn<<2];
void pushdown(int rt,int l,int r) {
int mid = (l+r)>>1;
if(setv[rt] > 0) {
int val = setv[rt];
minv[rt<<1] = maxv[rt<<1] = val;
sumv[rt<<1] = val*(mid-l+1);
minv[rt<<1|1] = maxv[rt<<1|1] = val;
sumv[rt<<1|1] = val*(r-mid);
setv[rt<<1|1] = setv[rt<<1] = val;
addv[rt<<1|1] = addv[rt<<1] = 0;
setv[rt] = 0;
}
if(addv[rt] > 0) {
minv[rt<<1] += addv[rt]; minv[rt<<1|1] += addv[rt];
maxv[rt<<1] += addv[rt]; maxv[rt<<1|1] += addv[rt];
sumv[rt<<1] += addv[rt]*(mid-l+1); sumv[rt<<1|1] += addv[rt]*(r-mid);
addv[rt<<1] += addv[rt];
addv[rt<<1|1] += addv[rt];
addv[rt] = 0;
}
}
void pushup(int rt) {
minv[rt] = min(minv[rt<<1], minv[rt<<1|1]);
maxv[rt] = max(maxv[rt<<1], maxv[rt<<1|1]);
sumv[rt] = sumv[rt<<1]+sumv[rt<<1|1];
}
void updateAdd(int L,int R,int v,int l,int r,int rt) {
if(L > r || R < l) {
return;
}
if(L <= l && r <= R) {
int add = (r-l+1)*v;
sumv[rt] += add;
addv[rt] += v;
minv[rt] += v;
maxv[rt] += v;
return;
}
pushdown(rt,l,r);
int mid = (l+r)>>1;
updateAdd(L,R,v,lson);
updateAdd(L,R,v,rson);
pushup(rt);
}
void updateSet(int L,int R,int v,int l,int r,int rt) {
if(L > r || R < l) {
return ;
}
if(L <= l && r <= R) {
int val = (r-l+1)*v;
sumv[rt] = val;
minv[rt] = maxv[rt] = v;
addv[rt] = 0;
setv[rt] = v;
return;
}
pushdown(rt,l,r);
int mid = (l+r) >> 1;
updateSet(L,R,v,lson);
updateSet(L,R,v,rson);
pushup(rt);
}
int _sum, _min, _max;
void query(int L,int R,int l,int r,int rt) {
if(L > r || R < l) {
return;
}
if(L <= l && r <= R) {
_sum += sumv[rt];
_min = min(_min, minv[rt]);
_max = max(_max, maxv[rt]);
return;
}
pushdown(rt,l,r);
int mid = (l+r)>>1;
query(L,R,lson);
query(L,R,rson);
pushup(rt);
}
int main() {
// freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&r,&c,&m)==3) {
memset(sumv, 0, sizeof sumv);
memset(minv, 0,sizeof minv);
memset(maxv, 0, sizeof maxv);
memset(addv,0,sizeof addv);
memset(setv,0,sizeof setv);
int op,x1,x2,y1,y2,v;
int n = r*c;
// cout << n << endl;
for(int i = 0; i < m; ++i) {
scanf("%d", &op);
if(op == 1) {
scanf("%d%d%d%d", &x1,&y1,&x2,&y2);
scanf("%d", &v);
// cout << x1 <<" " << x2 << endl;
for(int j = x1; j <= x2; ++j) {
int l = (j-1)*c+y1;
int r = (j-1)*c+y2;
// cout << l << " " << r << endl;
updateAdd(l,r,v,1,n,1);
}
}
else if(op == 2) {
scanf("%d%d%d%d", &x1,&y1,&x2,&y2);
scanf("%d", &v);
for(int j = x1; j <= x2; ++j) {
int l = (j-1)*c+y1;
int r = (j-1)*c+y2;
updateSet(l,r,v,1,n,1);
}
}
else {
scanf("%d%d%d%d", &x1,&y1,&x2,&y2);
_sum = 0; _min = 1e9; _max = 0;
for(int j = x1; j <= x2; ++j) {
int l = (j-1)*c+y1;
int r = (j-1)*c+y2;
query(l,r,1,n,1);
// cout << _sum << endl;
}
printf("%d %d %d\n", _sum, _min, _max);
}
}
}
return 0;
}