uva 11992 Fast Matrix Operations(线段树,区间修改)

本文深入探讨了线段树的实现细节及其在解决复杂区间更新与查询问题中的应用。通过一个具体的编程示例,详细介绍了如何构建线段树、进行区间加法、设置区间值及查询区间最小值、最大值和总和的方法。

此题也是无数WA。

其中的各种细节处理,对理解线段树有很大的帮助。

给出一个数据的示例

input:

1 4 13
2 1 1 1 4 5
2 1 2 1 3 4
1 1 1 1 4 1
3 1 1 1 4
3 1 2 1 3
1 1 4 1 4 100
3 1 3 1 4
2 1 2 1 3 0
2 1 1 1 2 1
3 1 1 1 4
1 1 2 1 4 2
3 1 1 1 4
3 1 1 1 2

初始状态,各节点的minv,maxv,sumv为0,setv=-1

第一步操作


第二、三步操作后



第六步操作后


第八步操作后


第九步操作后


第十一步操作后



#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>
#include <time.h>
#include <errno.h>

using namespace std;

#define MIN(a, b) a < b ? a : b
#define MAX(a, b) a > b ? a : b
#define F(i, n) for (int i=0;i<(n);++i)
#define REP(i, s, t) for(int i=s;i<=t;++i)
#define UREP(i, s, t) for(int i=s;i>=t;--i)
#define REPOK(i, s, t, o) for(int i=s;i<=t && o;++i)
#define MEM0(addr, size) memset(addr, 0, size)
#define LBIT(x) x&-x

#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define eps 1e-15

#define MAXN 1000000
#define MAXM 20
#define MOD 20071027

typedef long long LL;

const double maxdouble = numeric_limits<double>::max();
const int INF = 0x7FFFFFFF;

const int maxnode = 1 << 21; // 修改以确保足够大
struct IntervalTree {
    int minv[maxnode + 1];
    int maxv[maxnode + 1];
    int sumv[maxnode + 1];
    int addv[maxnode + 1];
    int setv[maxnode + 1];
    int length;
    int p, v;
    int qL, qR;

    int _min, _max, _sum;

    void init(int n) {
        length = n;
    }
    //_query的封装
    void query(int L, int R) {
        qL = L;
        qR = R;
        _min = INF;
        _max = -INF;
        _sum = 0;
        _query(1, 1, length, 0);
    }

    void _query(int o, int L, int R, int add) {
        if (setv[o] >= 0) {
            _min = min(_min, minv[o]+add);
            _max = max(_max, maxv[o]+add);
            _sum += (min(R, qR) - max(L, qL) + 1)*(setv[o]+add+addv[o]);
            return;
        }
        if (qL <= L && qR >= R) {
            _min = min(_min, minv[o]+add);
            _max = max(_max, maxv[o]+add);
            _sum += sumv[o] + (R-L+1)*add;
        } else {
            int M = L + (R-L)/2;
            int lc = 2*o, rc = 2*o+1;
            if (qL <= M)
                _query(lc, L, M, add+addv[o]);
            if (qR > M)
                _query(rc, M+1, R, add+addv[o]);
        }
    }

    void add(int L, int R, int v) {
        this->v = v;
        qL = L;
        qR = R;
        _add(1, 1, length);
    }

    void _add(int o, int L, int R) {
        if (qL <= L && qR >= R) {
            addv[o] += v;
        } else {
            pushdown(o);
            int M = L + (R-L)/2;
            int lc = 2*o, rc = 2*o+1;
            if (qL <= M)
                _add(lc, L, M);
            else
                maintain(lc, L, M);
            if (qR > M)
                _add(rc, M+1, R);
            else
                maintain(rc, M+1, R);
        }
        maintain(o, L, R);
    }
    void setto(int L, int R, int v) {
        qL = L;
        qR = R;
        this->v  = v;
        _set(1, 1, length);
    }

    void _set(int o, int L, int R) {
        if (qL <= L && qR >= R) {
            setv[o] = v;
            addv[o] = 0; // set操作清除add
        } else {
            pushdown(o);
            int M = L + (R-L)/2;
            int lc = 2*o, rc = 2*o+1;
            if (qL <= M)
                _set(lc, L, M);
            else
                maintain(lc, L, M); // 要维护不递归的子树
            if (qR > M)
                _set(rc, M+1, R);
            else
                maintain(rc, M+1, R);
        }
        maintain(o, L, R);
    }

    void pushdown(int o) {
        int lc = o*2, rc = o*2+1;
        if (setv[o] >= 0) { // setv = -1 表示没有set
            setv[lc] = setv[rc] = setv[o];
            addv[lc] = addv[rc] = 0;
            setv[o] = -1;
        }
        if (addv[o] > 0) {
            addv[lc] += addv[o];
            addv[rc] += addv[o];
            addv[o] = 0;
        }
    }

    void maintain(int o, int L, int R) {
        int lc = 2*o, rc = 2*o+1;
        sumv[o] = minv[o] = maxv[o] = 0;
        if (setv[o] >= 0) {
            minv[o] = maxv[o] = setv[o] + addv[o];
            sumv[o] = (setv[o]+addv[o]) * (R-L+1);
            //addv[o] = 0;
            return;
        }
        if (R > L) {
            minv[o] = min(minv[lc], minv[rc]);
            maxv[o] = max(maxv[lc], maxv[rc]);
            sumv[o] = sumv[lc] + sumv[rc];
        }
        minv[o] += addv[o];
        maxv[o] += addv[o];
        sumv[o] += (R-L+1)*addv[o];
    }

    void build(int o, int L, int R) {
        if (L == R) {
             minv[o] = 0;//arr[L];
             maxv[o] = 0;//arr[L];
             sumv[o] = 0;//arr[L];
             addv[o] = 0;
             setv[o] = -1;
        } else {
            int M = L + (R-L)/2;
            int lc = 2*o, rc = 2*o+1;
            build(lc, L, M);
            build(rc, M+1, R);
            minv[o] = min(minv[lc], minv[rc]);
            maxv[o] = max(maxv[lc], maxv[rc]);
            sumv[o] = sumv[lc] + sumv[rc];
            addv[o] = 0;
            setv[o] = -1;
        }
    }
};

IntervalTree tree[21];

int main()
{
    int r, c, m;
    int op;
    int x1, y1, x2, y2, v;

    while(scanf("%d%d%d",&r,&c,&m) != EOF) {
        REP(i, 1, r) {
            tree[i].init(c);
            tree[i].build(1, 1, c);
        }
        F(i, m) {
            scanf("%d%d%d%d%d",&op,&x1,&y1,&x2,&y2);
            switch(op) {
        case 1:
            scanf("%d",&v);
            REP(j, x1, x2)
                tree[j].add(y1, y2, v);
            break;
        case 2:
            scanf("%d",&v);
            REP(j, x1, x2)
                tree[j].setto(y1, y2, v);
            break;
        case 3:
            REP(j, x1, x2)
                tree[j].query(y1, y2);
            int _min = INF;
            int _max = -INF;
            int sum = 0;
            REP(j, x1, x2) {
                _min = min(_min, tree[j]._min);
                _max = max(_max, tree[j]._max);
                sum  += tree[j]._sum;
            }
            printf("%d %d %d\n", sum, _min, _max);
            break;
            }
        }
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值