文章目录
原版刘汝佳的代码有很多maintain语句,个人感觉这样很不符合习惯,所以做出了修改,更符合我的习惯
1: 只保留一个update时的maintain语句
2:时刻记着延迟标记只是延迟往下的标记,并不延迟节点本身,时刻修改,当延迟标记下到某个地方,它的值就应该被修改
// UVa11992 Fast Matrix Operations(更易读、更具一般性的版本)
// Rujia Liu
// 注意:所有叶子上总是保留set标记而不会被清除(pushdown只能针对非叶结点),因此maintain函数对于叶子来说并不会重复累加addv[o]
// 本程序在query的时候进行了标记传递(即pushdown),更具一般性,代码可读性也更强,但执行效率较低
// 有兴趣的读者请参考代码仓库中的uva11992.cpp,那个写法是书上例题中的代码,避开了query中的标记传递,执行效率比本代码高
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxnode = 1<<17;
const int INF = 1000000000;
int op, x1, x2, y1, y2, x, v;
struct IntervalTree {
int sumv[maxnode], minv[maxnode], maxv[maxnode], setv[maxnode], addv[maxnode];
// 维护信息
void maintain(int o, int L, int R) {
int lc = o*2, rc = o*2+1;
if(R > L) {
sumv[o] = sumv[lc] + sumv[rc];
minv[o] = min(minv[lc], minv[rc]);
maxv[o] = max(maxv[lc], maxv[rc]);
}
if(setv[o] >= 0) { minv[o] = maxv[o] = setv[o]; sumv[o] = setv[o] * (R-L+1); }
if(addv[o]) { minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+1); }
}
// 标记传递
void pushdown(int o,int l,int r) {
int lc = o*2, rc = o*2+1;
int m = (l+r)>>1;
if(setv[o] >= 0) {
setv[lc] = setv[rc] = setv[o];
sumv[lc] = setv[o]*(m-l+1);
sumv[rc] = setv[o]*(r-m);
minv[lc] = minv[rc] = setv[o];
maxv[lc] = maxv[rc] = setv[o];
addv[lc] = addv[rc] = 0;
setv[o] = -1; // 清除本结点标记
}
if(addv[o]) {
sumv[lc] += addv[o]*(m-l+1);
sumv[rc] += addv[o]*(r-m);
minv[lc] += addv[o];
maxv[lc] += addv[o];
minv[rc] += addv[o];
maxv[rc] += addv[o];
addv[lc] += addv[o];
addv[rc] += addv[o];
addv[o] = 0; // 清除本结点标记
}
}
void update(int o, int L, int R) {
int lc = o*2, rc = o*2+1;
if(y1 <= L && y2 >= R) { // 标记修改
if(op == 1) {
addv[o] += v;
sumv[o] += (R-L+1)*v;
maxv[o] += v;
minv[o] += v;
}
else {
setv[o] = v; addv[o] = 0;
sumv[o] = (R-L+1)*v;
maxv[o] = v;
minv[o] = v;
}
} else {
pushdown(o,L,R);
int M = L + (R-L)/2;
if(y1 <= M) update(lc, L, M);//else maintain(lc, L, M);
if(y2 > M) update(rc, M+1, R);// else maintain(rc, M+1, R);
maintain(o, L, R);
}
}
void query(int o, int L, int R, int& ssum, int& smin, int &smax) {
int lc = o*2, rc = o*2+1;
//maintain(o, L, R); // 处理被pushdown下来的标记
if(y1 <= L && y2 >= R) {
ssum = sumv[o];
smin = minv[o];
smax = maxv[o];
} else {
pushdown(o,L,R);
int M = L + (R-L)/2;
int lsum = 0, lmin = INF, lmax = -INF;
int rsum = 0, rmin = INF, rmax = -INF;
if(y1 <= M) query(lc, L, M, lsum, lmin, lmax); //else maintain(lc, L, M);
if(y2 > M) query(rc, M+1, R, rsum, rmin, rmax); //else maintain(rc, M+1, R);
ssum = lsum + rsum;
smin = min(lmin, rmin);
smax = max(lmax, rmax);
}
}
};
const int maxr = 20 + 5;
IntervalTree tree[maxr];
int main() {
int r, c, m;
while(scanf("%d%d%d", &r, &c, &m) == 3) {
memset(tree, 0, sizeof(tree));
for(x = 1; x <= r; x++) {
memset(tree[x].setv, -1, sizeof(tree[x].setv));
tree[x].setv[1] = 0;
}
while(m--) {
scanf("%d%d%d%d%d", &op, &x1, &y1, &x2, &y2);
if(op < 3) {
scanf("%d", &v);
for(x = x1; x <= x2; x++) tree[x].update(1, 1, c);
} else {
int gsum = 0, gmin = INF, gmax = -INF;
for(x = x1; x <= x2; x++) {
int ssum, smin, smax;
tree[x].query(1, 1, c, ssum, smin, smax);
gsum += ssum; gmin = min(gmin, smin); gmax = max(gmax, smax);
}
printf("%d %d %d\n", gsum, gmin, gmax);
}
}
}
return 0;
}