UVA11992 Fast Matrix Operations(线段树)

题目链接:点击链接

题意:

  • 给一个矩阵,有三个操作。操作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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值