Submission #1162245

#TimeUsernameProblemLanguageResultExecution timeMemory
1162245with_wageeh원숭이와 사과 나무 (IZhO12_apple)C++20
100 / 100
244 ms69164 KiB
#include <bits/stdc++.h>
using namespace std;

// SparseSegtree is designed for very large ranges (for example up to 1e9)
// but only creates nodes for segments that are updated or queried.
// It supports range "set" updates (assigning a given value to every element in a range)
// and range sum queries.
class SparseSegtree {
private:
    // Each node stores:
    //   - freq: the aggregate value (here, the sum of the segment)
    //   - lazy: a lazy propagation marker (nonzero means that the node’s segment
    //           should be updated to that value)
    //   - left, right: indices in the tree vector for the left and right children.
    struct Node {
        int freq = 0;   // sum of the segment
        int lazy = 0;   // lazy marker for range-set updates; 0 means no pending update
        int left = -1;  // index of left child in the tree vector (-1 if not created)
        int right = -1; // index of right child (-1 if not created)
    };

    vector<Node> tree; // the collection of nodes (dynamically allocated as needed)
    const int n;       // size of the overall range [0, n-1]
    int timer = 0;     // used to assign indices for new nodes

    // Combine two segment values.
    // For a sum query, simply add the two values.
    inline int comb(int a, int b) {
        return a + b;
    }

    // Apply a range-set update to the current node.
    // 'cur' is the current node index.
    // 'len' is the length of the segment represented by this node.
    // 'val' is the value we want to assign over the entire segment.
    inline void apply(int cur, int len, int val) {
        // Set the lazy marker (indicating that the whole segment is updated to 'val')
        tree[cur].lazy = val;
        // Update the aggregate value (frequency) of this node.
        tree[cur].freq = len * val;
    }

    // Propagate the lazy update from the current node down to its children.
    // 'l' and 'r' represent the current segment boundaries.
    inline void push_down(int cur, int l, int r) {
        // Create left child if it doesn't exist
        if (tree[cur].left == -1) {
            tree[cur].left = ++timer;
            tree.push_back(Node());
        }
        // Create right child if it doesn't exist
        if (tree[cur].right == -1) {
            tree[cur].right = ++timer;
            tree.push_back(Node());
        }
        int m = (l + r) / 2;  // mid-point of the segment

        // If there is a pending lazy update on the current node, push it to both children.
        if (tree[cur].lazy != 0) {
            apply(tree[cur].left, m - l + 1, tree[cur].lazy);
            apply(tree[cur].right, r - m, tree[cur].lazy);
            // Clear the lazy marker after propagation.
            tree[cur].lazy = 0;
        }
    }

    // Internal function to perform a range-set update.
    // It sets every element in the interval [ql, qr] to 'val'.
    // cur: current node index; [l, r] is the segment for this node.
    void range_set(int cur, int l, int r, int ql, int qr, int val) {
        // No overlap: simply return.
        if (qr < l || ql > r)
            return;
        // Total overlap: directly apply the update.
        if (ql <= l && r <= qr) {
            apply(cur, r - l + 1, val);
        } else {
            // Partial overlap: first push down any pending lazy updates.
            push_down(cur, l, r);
            int m = (l + r) / 2;
            // Recurse to left child.
            range_set(tree[cur].left, l, m, ql, qr, val);
            // Recurse to right child.
            range_set(tree[cur].right, m + 1, r, ql, qr, val);
            // Combine results from children.
            tree[cur].freq = comb(tree[tree[cur].left].freq, tree[tree[cur].right].freq);
        }
    }

    // Internal function to compute the range sum over [ql, qr].
    // cur: current node index; [l, r] is the segment for this node.
    int range_sum(int cur, int l, int r, int ql, int qr) {
        // No overlap.
        if (qr < l || ql > r)
            return 0;
        // Total overlap.
        if (ql <= l && r <= qr)
            return tree[cur].freq;
        // Partial overlap: push down pending updates and combine query results.
        push_down(cur, l, r);
        int m = (l + r) / 2;
        return comb(range_sum(tree[cur].left, l, m, ql, qr),
                    range_sum(tree[cur].right, m + 1, r, ql, qr));
    }

public:
    // Constructor:
    // 'n' is the overall size of the range.
    // 'q' (optional) is the expected number of queries, used to reserve space.
    SparseSegtree(int n, int q = 0) : n(n) {
        // Reserve extra space in the vector if a query count is given.
        if (q > 0)
            tree.reserve(2 * q * __lg(n));
        // Create the root node which covers the whole range [0, n-1].
        tree.push_back(Node());
    }

    // Public interface for range_set update:
    // Sets all elements in the interval [ql, qr] to 'val'.
    void range_set(int ql, int qr, int val) {
        range_set(0, 0, n - 1, ql, qr, val);
    }

    // Public interface for range_sum query:
    // Returns the sum of values in the interval [ql, qr].
    int range_sum(int ql, int qr) {
        return range_sum(0, 0, n - 1, ql, qr);
    }
};

//////////////////////////
/// Main Program Demo  ///
//////////////////////////
int main() {
    int query_num;
    cin >> query_num;
    // In this example, we assume the overall range is 1e9 (rails numbered 0..1e9)
    const int RANGE_SIZE = 1e9;
    // Create the sparse segment tree.
    // We add 1 to RANGE_SIZE to cover [0, RANGE_SIZE] and pass the query count to reserve space.
    SparseSegtree st(RANGE_SIZE + 1, query_num);

    // 'c' is used to adjust query indices based on previous query results (a common technique in interactive problems).
    int c = 0;
    for (int i = 0; i < query_num; i++) {
        int type, x, y;
        cin >> type >> x >> y;
        // Query: when type == 1, perform a range sum query.
        if (type == 1) {
            // Adjust the query interval using c.
            c = st.range_sum(x + c, y + c);
            cout << c << '\n';
        }
            // Update: when type == 2, perform a range-set update.
            // For the red-ripening event, the update value is 1.
        else if (type == 2) {
            st.range_set(x + c, y + c, 1);
        }
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...