Submission #1280395

#TimeUsernameProblemLanguageResultExecution timeMemory
1280395heymynameiskiraFood Court (JOI21_foodcourt)C++20
100 / 100
400 ms44388 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

class Fenwick {
    private:
        vector<ll> val;
    public:
        Fenwick(int n) : val(n+1, 0) {}

        // Adds v to index i
        void add(int i, ll v) {
            for (++i; i < val.size(); i += i & -i) {
                val[i] += v;
            }
        }

        // Calculates prefix sum up to index i
        ll get(int i) {
            ll res = 0;
            for (++i; i > 0; i -= i & -i) {
                res += val[i];
            }
            return res;
        }
        ll get(int a, int b) { return get(b) - get(a-1); }
};

// Segment tree for range minimum and addition.
class SegTree {
    private:
        const ll NEUT = 4 * (ll)1e18;
        vector<ll> seg, tag;
        int h = 1;

        void apply(int i, ll v) {
            seg[i] += v;
            if (i < h) tag[i] += v;
        }
        void push(int i) {
            if (tag[i] == 0) return;
            apply(2*i, tag[i]);
            apply(2*i+1, tag[i]);
            tag[i] = 0;
        }
        ll combine(ll a, ll b) { return min(a, b); }

        ll recGet(int a, int b, int i, int ia, int ib) {
            if (ib <= a || b <= ia) return NEUT;
            if (a <= ia && ib <= b) return seg[i];
            push(i);
            int im = (ia + ib) >> 1;
            return combine(
                recGet(a, b, 2*i, ia, im),
                recGet(a, b, 2*i+1, im, ib));
        }
        void recApply(int a, int b, ll v, int i, int ia, int ib) {
            if (ib <= a || b <= ia) return;
            if (a <= ia && ib <= b) apply(i, v);
            else {
                push(i);
                int im = (ia + ib) >> 1;
                recApply(a, b, v, 2*i, ia, im);
                recApply(a, b, v, 2*i+1, im, ib);
                seg[i] = combine(seg[2*i], seg[2*i+1]);
            }
        }
        int recFind(int a, int b, ll v, int i, int ia, int ib) {
            if (seg[i] > v) return b;
            if (b <= ia || ib <= a) return b;
            if (ib == ia + 1) return ia;

            push(i);
            int im = (ia + ib) >> 1;
            int off = recFind(a, b, v, 2*i, ia, im);
            if (off < b) return off;
            else return recFind(a, b, v, 2*i+1, im, ib);
        }
    public:
        SegTree(int n) {
            while(h < n) h *= 2;
            seg.resize(2*h, 0);
            tag.resize(h, 0);
        }
        ll rangeMin(int a, int b) { return recGet(a, b+1, 1, 0, h); }
        void rangeAdd(int a, int b, ll v) { recApply(a, b+1, v, 1, 0, h); }
        int findNext(int a, int b, ll v) { return recFind(a, b+1, v, 1, 0, h); }
};

struct SegTreeBeats {
private:
    struct Node {
        ll add;   // pending range add to push to children
        ll cap;   // node value capped by ceilings from ancestors
        Node(): add(0), cap(0) {}
    };

    const ll INF = 4 * (ll)1e18;

    int n;                   // number of leaves (power of two not required)
    std::vector<Node> st;    // 4*n is fine in this style

    // same semantics as original:
    // "add a, then clamp by c" on the current node
    inline void apply(int head, ll a, ll c) {
        st[head].cap = std::min(st[head].cap + a, c);
        st[head].add += a;             // add is only for children (will be used in push)
    }

    // push parent's (add, cap) to children, then clear parent tags
    inline void push(int head) {
        // left child
        apply(head << 1,     st[head].add, st[head].cap);
        // right child
        apply(head << 1 | 1, st[head].add, st[head].cap);

        // clear tags on this node
        st[head].add = 0;
        st[head].cap = INF;      // after pushing, the parent's own ceiling becomes "no ceiling"
    }

    // range add (pure add because we pass c = +INF at covered nodes)
    void recAdd(int head, int l, int r, int ql, int qr, ll v) {
        if (r <= ql || qr <= l) return;
        if (ql <= l && r <= qr) {
            apply(head, v, INF); // add only (no cap)
            return;
        }
        push(head);
        int mid = (l + r) >> 1;
        recAdd(head << 1,     l, mid, ql, qr, v);
        recAdd(head << 1 | 1, mid, r, ql, qr, v);
        // no pull step: the structure's query returns st[head].cap directly
    }

    // query max over [ql, qr) — identical to the original recMax behavior
    ll recMax(int head, int l, int r, int ql, int qr) {
        if (r <= ql || qr <= l) return -INF;
        if (ql <= l && r <= qr) return st[head].cap;
        push(head);
        int mid = (l + r) >> 1;
        return std::max(recMax(head << 1, l, mid, ql, qr),
                        recMax(head << 1 | 1, mid, r, ql, qr));
    }

public:
    // n = logical size (0..n-1). We allocate 4*n nodes like your usual style.
    SegTreeBeats(int n): n(n) {
        st.assign(4 * n + 5, Node());
        // all nodes start with add=0, cap=0 (same as original)
    }

    // add v to [a, b] inclusive (original code uses [a, b+1) under the hood)
    void rangeAdd(int a, int b, ll v) {
        recAdd(1, 0, n, a, b + 1, v);
        // impose "global ceiling 0" at the root (exactly like the original apply(1,0,0))
        apply(1, 0, 0);
    }

    // point get at i (returns min(A[i], current_root_ceiling))
    ll get(int i) {
        return recMax(1, 0, n, i, i + 1);
    }
};
const string name = "test";

int main() {
    if (fopen((name + ".inp").c_str(), "r"))
    {
        freopen((name + ".inp").c_str(), "r", stdin);
        freopen((name + ".out").c_str(), "w", stdout);
    }
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    int n, m, q;
    cin >> n >> m >> q;

    SegTreeBeats cur(n);
    Fenwick tot(n+1);

    vector<int> res;
    vector<vector<pair<ll, int>>> qs(n);
    vector<array<ll, 5>> ops(q);

    for (int qi = 0; qi < q; ++qi) {
        cin >> ops[qi][0];

        ll a, b;
        cin >> a >> b;
        --a; --b;
        ops[qi][1] = a; ops[qi][2] = b;

        if (ops[qi][0] == 1) {
            ll c, k;
            cin >> c >> k;
            ops[qi][3] = c; ops[qi][4] = k;

            cur.rangeAdd(a, b, -k);
            tot.add(a, k);
            tot.add(b+1, -k);

        } else if (ops[qi][0] == 2) {
            ll k;
            cin >> k;
            ops[qi][3] = k;

            cur.rangeAdd(a, b, k);

        } else if (ops[qi][0] == 3) {
            ++b;
            ll v = -cur.get(a);

            int ind = res.size();
            res.emplace_back(0);
            if (v >= b) qs[a].emplace_back(tot.get(a) - (v - b), ind);
        }

    }

    const ll INF = 1e18;
    SegTree groups(n);
    vector<int> inds(n, 0);
    for (int i = 0; i < n; ++i) {
        if (qs[i].empty()) {
            groups.rangeAdd(i, i, INF);
        } else {
            sort(qs[i].begin(), qs[i].end());
            groups.rangeAdd(i, i, qs[i][0].first);
        }
    }

    for (int qi = 0; qi < q; ++qi) {
        int t = ops[qi][0];
        if (t == 1) {
            ll a = ops[qi][1]; ll b = ops[qi][2];
            ll c = ops[qi][3]; ll k = ops[qi][4];

            groups.rangeAdd(a, b, -k);
            while(true) {
                int j = groups.findNext(0, n-1, 0);
                if (j == n) break;

                res[qs[j][inds[j]].second] = c;
                ++inds[j];
                if (inds[j] >= qs[j].size()) {
                    groups.rangeAdd(j, j, INF);
                } else {
                    groups.rangeAdd(j, j, qs[j][inds[j]].first - qs[j][inds[j] - 1].first);
                }
            }
        }
    }

    for (auto c : res) cout << c << '\n';
}

Compilation message (stderr)

foodcourt.cpp: In function 'int main()':
foodcourt.cpp:170:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  170 |         freopen((name + ".inp").c_str(), "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
foodcourt.cpp:171:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  171 |         freopen((name + ".out").c_str(), "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...