ABC382 C-F題解

XYukari發表於2024-12-07

C - Kaiten Sushi

把壽司都放到一個堆裡,從前往後掃 \(A\) 陣列,如果當前食客 \(A_i\) 小於等於堆頂,就取出堆頂,記錄這份壽司被第 \(i\) 個人吃掉。複雜度 \(O(n\log m)\)

D - Keep Distance

搜尋回溯,但每一步從 \(10\) 列舉到 \(m\) 會超時,剪一下枝 for (int i = 10; res.back() + i <= m - 10 * (n - siz - 1); i++)

F - Falling Stars

把橫線從下到上排序,開一棵線段樹記錄每個位置摞了多少層。要加入一條橫線的時候,先查詢對應區間 \([C_i,C_i+L_i-1]\) 的最小值(最高層數)\(r\),則該橫線的層數就是 \(r-1\),區間賦值 \(r-1\) 即可。

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

int main() {
    cin.tie(0)->sync_with_stdio(0);
    int H, W, n;
    cin >> H >> W >> n;
    struct Bar {
        int R, C, L, id;
        bool operator<(const Bar& o) const {
            return R > o.R;
        }
    };
    vector<Bar> bars(n);
    for (int i = 0; i < n; i++) {
        Bar& b = bars[i];
        cin >> b.R >> b.C >> b.L;
        b.id = i;
    }
    sort(bars.begin(), bars.end());
    class SegmentTree {
        struct Node;
        using NodePtr = shared_ptr<Node>;

        struct Node {
            int l, r, val, tag;
            NodePtr ls, rs;
            Node(int l, int r, int val, int tag,
                 NodePtr ls = nullptr,
                 NodePtr rs = nullptr)
                : l(l), r(r), val(val), tag(tag), ls(ls), rs(rs) {}
        };

       private:
        NodePtr root;
        void refresh(NodePtr p) {
            p->val = min(p->ls->val, p->rs->val);
        }
        void build(NodePtr& p, int l, int r) {
            p = make_shared<Node>(l, r, 0, 0);
            if (l == r) return;
            int mid = (l + r) >> 1;
            build(p->ls, l, mid);
            build(p->rs, mid + 1, r);
        }
        void applyFillTag(NodePtr p, int v) {
            p->val = p->tag = v;
        }
        void pushDown(NodePtr p) {
            if (!p->tag) return;
            applyFillTag(p->ls, p->tag);
            applyFillTag(p->rs, p->tag);
            p->tag = 0;
        }
        void fillRange(NodePtr p, int l, int r, int val) {
            if (l <= p->l && p->r <= r)
                return applyFillTag(p, val), void(0);
            pushDown(p);
            int mid = (p->l + p->r) >> 1;
            if (l <= mid) fillRange(p->ls, l, r, val);
            if (r > mid) fillRange(p->rs, l, r, val);
            refresh(p);
        }
        int queryMin(NodePtr p, int l, int r) {
            if (l <= p->l && p->r <= r)
                return p->val;
            pushDown(p);
            int mid = (p->l + p->r) >> 1;
            int res = INT_MAX;
            if (l <= mid) res = min(res, queryMin(p->ls, l, r));
            if (r > mid) res = min(res, queryMin(p->rs, l, r));
            return res;
        }

       public:
        SegmentTree(int l, int r) { build(root, l, r); }
        void fillRange(int l, int r, int val) { fillRange(root, l, r, val); }
        int queryMin(int l, int r) { return queryMin(root, l, r); }
    };
    SegmentTree tr(1, W);
    tr.fillRange(1, W, H + 1);
    vector<int> ans(n);
    for (auto& b : bars) {
        ans[b.id] = tr.queryMin(b.C, b.C + b.L - 1) - 1;
        tr.fillRange(b.C, b.C + b.L - 1, ans[b.id]);
    }
    for (int i = 0; i < n; i++) {
        cout << ans[i] << '\n';
    }
    return 0;
}