【补题】UVA11992 Fast Matrix Operations(使用类包装的线段树)

本文介绍了一种使用线段树解决二维矩阵操作的算法,针对矩阵不超过20行的情况,每行建立一棵线段树进行维护。算法包括区间加法、区间赋值和区间查询操作,确保了高效的数据更新和查询。代码实现中采用了动态开点的线段树模板,实现了区间加法、区间赋值和区间查询的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UVA11992 Fast Matrix Operations

前置芝士

  • 线段树
  • 多颗线段树

题目传送门

题目大意

需要对一个初始全为0的矩阵进行操作。给定两个点,并执行下面三个操作:

  • 对给定两个点中间的范围加上val
  • 将给定两个点中间的范围全部赋值为val
  • 询问给定两个点中间的范围中所有元素的和和其中的最大值与最小值。

矩阵不超过20行

思路

因为矩阵不超过20行,可以考虑每一行直接开一棵线段树进行维护。

区间加法与查询

区间加法和查询很简单,只需要参照正常线段树,一颗一颗维护就行。

  • 要注意的一点,区间加法对于最大值和最小值也需要同时加上。

区间赋值

对于区间赋值,需要注意其与区间加法和维护区间最值得关系:

  • 区间赋值的更新必须要在区间加法之前,且区间加法的标记在区间赋值进行后需要清空(不管之前加了多少值赋值一下就没了正常吧)。
  • 区间赋值的时候区间最值也要直接更改。

开多颗线段树

因为要开多棵树,因此将线段树直接包装成类会更好(但是代码量大涨)。

具体代码实现

一种可行的代码实现如下。

下面这种可行的线段树模板用的是动态开点而不是堆式存储。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

class seg {
    private:
        struct Node {
            ll val;
            ll minn, maxn;
            ll mkad, mkch;
            int lc, rc;
            Node() {
                val = mkad = mkch = lc = rc = 0;
                mkad = mkch = 0;
            }
        };
        void update(int now) {
            tr[now].val = tr[tr[now].lc].val + tr[tr[now].rc].val;
            tr[now].minn = min(tr[tr[now].lc].minn, tr[tr[now].rc].minn);
            tr[now].maxn = max(tr[tr[now].lc].maxn, tr[tr[now].rc].maxn);
        }
        void pushdown(int pll, int prr, int now) {
            int mid = pll + ((prr - pll) >> 1);
            if (tr[now].mkch) {
                tr[tr[now].lc].val = (mid - pll + 1) * tr[now].mkch;
                tr[tr[now].lc].maxn = tr[tr[now].lc].minn = tr[now].mkch;
                tr[tr[now].lc].mkch = tr[now].mkch;
                tr[tr[now].rc].val = (prr - mid) * tr[now].mkch;
                tr[tr[now].rc].maxn = tr[tr[now].rc].minn = tr[now].mkch;
                tr[tr[now].rc].mkch = tr[now].mkch;
                tr[tr[now].lc].mkad = tr[tr[now].rc].mkad = 0;
                tr[now].mkch = 0;
            }
            if (tr[now].mkad) {
                tr[tr[now].lc].val += (mid - pll + 1) * tr[now].mkad;
                tr[tr[now].lc].maxn += tr[now].mkad;
                tr[tr[now].lc].minn += tr[now].mkad;
                tr[tr[now].lc].mkad += tr[now].mkad;
                tr[tr[now].rc].val += (prr - mid) * tr[now].mkad;
                tr[tr[now].rc].maxn += tr[now].mkad;
                tr[tr[now].rc].minn += tr[now].mkad;
                tr[tr[now].rc].mkad += tr[now].mkad;
                tr[now].mkad = 0;
            }
        }
        vector<Node>tr;
        int tot, root;
        int n;
        void build(int pll, int prr, int now) {
            if (pll == prr) {
                tr[now].maxn = tr[now].minn = 0;
                tr[now].lc = tr[now].rc = 0;
                tr[now].val = tr[now].mkad = tr[now].mkch = 0;
                return;
            }
            int mid = pll + ((prr - pll) >> 1);
            tr[now].lc = ++ tot;
            build(pll, mid, tr[now].lc);
            tr[now].rc = ++ tot;
            build(mid + 1, prr, tr[now].rc);
            update(now);
        }
        void add(int sll, int srr, ll val, int pll, int prr, int now) {
            if (sll <= pll && srr >= prr) {
                tr[now].val += (prr - pll + 1) * val;
                tr[now].maxn += val;
                tr[now].minn += val;
                tr[now].mkad += val;
                return;
            }
            int mid = pll + ((prr - pll) >> 1);
            pushdown(pll, prr, now);
            if (sll <= mid) {
                add(sll, srr, val, pll, mid, tr[now].lc);
            }
            if (srr > mid) {
                add(sll, srr, val, mid + 1, prr, tr[now].rc);
            }
            update(now);
        }
        void change(int sll, int srr, ll val, int pll, int prr, int now) {
            if (sll <= pll && srr >= prr) {
                tr[now].val = (prr - pll + 1) * val;
                tr[now].maxn = tr[now].minn = val;
                tr[now].mkch = val;
                tr[now].mkad = 0;
                return;
            }
            int mid = pll + ((prr - pll) >> 1);
            pushdown(pll, prr, now);
            if (sll <= mid) {
                change(sll, srr, val, pll, mid, tr[now].lc);
            }
            if (srr > mid) {
                change(sll, srr, val, mid + 1, prr, tr[now].rc);
            }
            update(now);
        }
        tuple<ll, ll, ll> query(int sll, int srr, int pll, int prr, int now) {
            if (sll <= pll && srr >= prr) {
                return make_tuple(tr[now].val, tr[now].maxn, tr[now].minn);
            }
            int mid = pll + ((prr - pll) >> 1);
            pushdown(pll, prr, now);
            ll sum = 0, maxn = 0, minn = 1 << 30;
            if (sll <= mid) {
                auto [a, b, c] = query(sll, srr, pll, mid, tr[now].lc);
                sum += a; maxn = max(maxn, b); minn = min(minn, c);
            }
            if (srr > mid) {
                auto [a, b, c] = query(sll, srr, mid + 1, prr, tr[now].rc);                
                sum += a; maxn = max(maxn, b); minn = min(minn, c);
            }
            return make_tuple(sum, maxn, minn);
        }
    public:
        void inti(int siz) {
            n = siz;
            tr.assign(siz << 4, Node());
            tot = root = 1;
            build(1, n, root);
        }
        void add(int sll, int srr, ll val) {
            add(sll, srr, val, 1, n, root);
        }
        void change(int sll, int srr, ll val) {
            change(sll, srr, val, 1, n, root);
        }
        tuple<ll, ll, ll> query(int sll, int srr) {
            return query(sll, srr, 1, n, root);
        }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
        
    int r, c, t;
    cin >> r >> c >> t;

    vector<seg>tr(r + 1);

    for (int i = 1; i <= r; ++ i) {
        tr[i].inti(c);
    }

    while (t --) {
        int c, x1, y1, x2, y2;
        ll val;
        cin >> c >> x1 >> y1 >> x2 >> y2;
        if (c == 1) {
            cin >> val;
            for (int i = x1; i <= x2; ++ i) {
                tr[i].add(y1, y2, val);
            }
        } else if (c == 2) {
            cin >> val;
            for (int i = x1; i <= x2; ++ i) {
                tr[i].change(y1, y2, val);
            }
        } else {
            ll sum = 0, maxn = 0, minn = 1 << 30;
            for (int i = x1; i <= x2; ++ i) {
                auto [a, b, c] = tr[i].query(y1, y2);
                sum += a; maxn = max(maxn, b); minn = min(minn, c);
            }
            cout << sum << ' ' << minn << ' ' << maxn << '\n';
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值