题目链接:点击链接
题意:
- 给一个矩阵,有三个操作。操作1,将这个矩阵的一个子矩阵的值全加上v。操作2,将这个矩阵的一个子矩阵的值全置为v。操作3,求这个矩阵的一个子矩阵的最大值,最小值,和。
思路:
看似很简单的set和add操作,我这个线段树菜鸡,卡了很久。前几天写另一道线段树时,突然明白set操作和add操作先后顺序对答案的影响。
都明白先add后set,前面的add会被置0,执行Set操作的时候,懒标记setv被置为v,懒标记addv被置为0。那么在push down的时候,会不会遇到setv和addv都不为0的情况?会的,这是先set后add的情况,此时两个标记都不为空,那么在push down操作里一定要先push down setv标记,把左儿子,右儿子的addv置0,再push down addv标记。所以push down函数里不能是if-else if的关系,而是if-if的关系。
那这样的push down函数会不会对先add后set产生影响?不会,因为每次Set的时候,都把addv置0了。即先add后set,addv为0,setv为v,先set后add,addv和setv都不为0。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1e6+100;
long long _max, _min, _sum;
class SegmentTree
{
public:
int minv[maxn<<2];
int maxv[maxn<<2];
int addv[maxn<<2];
int setv[maxn<<2];
int sumv[maxn<<2];
SegmentTree(){}
void build(){
memset(minv, 0, sizeof(minv));
memset(maxv, 0, sizeof(maxv));
memset(addv, 0, sizeof(addv));
memset(setv, 0, sizeof(setv));
memset(sumv, 0, sizeof(sumv));
}
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 pushdown(int rt, int len){
if(setv[rt]!=0){
addv[rt<<1] = addv[rt<<1|1] = 0;
setv[rt<<1] = setv[rt<<1|1] = setv[rt];
minv[rt<<1] = minv[rt<<1|1] = setv[rt];
maxv[rt<<1] = maxv[rt<<1|1] = setv[rt];
sumv[rt<<1] = (len - len/2) * setv[rt];
sumv[rt<<1|1] = (len/2) * setv[rt];
setv[rt] = 0;
}
if(addv[rt]!=0){
addv[rt<<1] += addv[rt];
minv[rt<<1] += addv[rt];
maxv[rt<<1] += addv[rt];
sumv[rt<<1] += (len - len/2) * addv[rt];
addv[rt<<1|1] += addv[rt];
minv[rt<<1|1] += addv[rt];
maxv[rt<<1|1] += addv[rt];
sumv[rt<<1|1] += (len/2) * addv[rt];
addv[rt] = 0;
}
}
void Add(int rt, int a, int b, int l, int r,int x){
if(a<=l && r<=b){
sumv[rt] += (r-l+1) * x;
minv[rt] += x;
maxv[rt] += x;
addv[rt] += x;
}
else{
pushdown(rt, r-l+1);
int mid = (l+r)>>1;
if(a<=mid) Add(rt<<1, a, b, l, mid, x);
if(mid<b) Add(rt<<1|1, a, b, mid+1, r, x);
pushup(rt);
}
}
void Set(int rt, int a, int b, int l, int r, int x){
if(a<=l && r<=b){
sumv[rt] = (r-l+1) * x;
minv[rt] = x;
maxv[rt] = x;
addv[rt] = 0;
setv[rt] = x;
}
else{
pushdown(rt, r-l+1);
int mid = (l+r)>>1;
if(a<=mid) Set(rt<<1, a, b, l, mid, x);
if(mid<b) Set(rt<<1|1, a, b, mid+1, r, x);
pushup(rt);
}
}
void query(int rt, int a, int b, int l, int r){
if(a<=l && r<=b){
_sum += sumv[rt];
_min = min(_min, (long long)minv[rt]);
_max = max(_max, (long long)maxv[rt]);
}
else{
pushdown(rt, r-l+1);
int mid = (l+r)>>1;
if(a<=mid) query(rt<<1, a, b, l, mid);
if(mid<b) query(rt<<1|1, a, b, mid+1, r);
pushup(rt);
}
}
}matrix[22];
int main(){
int r, c, m, opt, x1, y1, x2, y2, v;
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
while(scanf("%d%d%d", &r, &c, &m)!=EOF){
for(int i=1; i<=r; ++i) matrix[i].build();
for(int j=0; j<m; ++j){
scanf("%d", &opt);
if(opt==1){
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &v);
for(int i=x1; i<=x2; ++i){
matrix[i].Add(1, y1, y2, 1, c, v);
}
}
if(opt==2){
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &v);
for(int i=x1; i<=x2; ++i){
matrix[i].Set(1, y1, y2, 1, c, v);
}
}
if(opt==3){
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
_sum = 0; _min = 0x3f3f3f3f; _max = -0x3f3f3f3f;
for(int i=x1; i<=x2; ++i){
matrix[i].query(1, y1, y2, 1, c);
}
printf("%lld %lld %lld\n", _sum, _min, _max);
}
}
}
return 0;
}