目录

算法线段树的应用-力扣3479.-将水果装入篮子-III

目录

【算法】线段树的应用-力扣3479. 将水果装入篮子 III

这个题就是线段树的应用,但是与之前的文章相比,此处构建的线段树相当于“最大树”,每个节点存储的不是子节点的和,而是子节点中的最大值。

#include <bit>
class SegmentTree {
    vector<int> mx;

    void maintain(int o) {
        // 根据不同的线段树的需求修改对应的代码,
        // 本题需要找到最左边最大的点,因此需要构建最大线段树
        mx[o] = max(mx[o * 2], mx[o * 2 + 1]);
    }

    void build(const vector<int>& a, int o, int l, int r) {
        if(l == r) {
            mx[o] = a[l];
            return;
        }
        int m = (l + r) / 2;
        build(a, o * 2, l, m);
        build(a, o * 2 + 1, m + 1, r);
        maintain(o);
    }
    public:
    SegmentTree(const vector<int>& a) {
        size_t n = a.size();
        mx.resize(2 << bit_width(n - 1));
        build(a, 1, 0, n - 1);
    }

    int findFirstAndUpdate(int o, int l, int r, int x) {
        if(mx[o] < x) {
            return -1;
        }
        if(l == r) {
            mx[o] = -1;
            return l;
        }
        int m = (l + r) / 2;
        int i = findFirstAndUpdate(o * 2, l, m, x);
        if(i < 0) {
            i = findFirstAndUpdate(o * 2 + 1, m + 1, r, x);
        }
        // 注意更新线段树上部的信息
        maintain(o);
        return i;
    }
};

class Solution {
public:
    int numOfUnplacedFruits(vector<int>& fruits, vector<int>& baskets) {
        SegmentTree t(baskets);
        int n = baskets.size(), result = 0;
        for(auto x : fruits) {
            if(t.findFirstAndUpdate(1, 0, n - 1, x) < 0) {
                result++;
            }
        }
        return result;
    }
};

注意此处就涉及到之前说的那个s + t 会溢出的问题,因此不能用移位操作来实现。