Submission #70306484


Source Code Expand

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <numeric>
#include <stack>
#include <cassert>
#include <cstring>
#include <cmath>
#include <random>
#include <unordered_map>
#include <unordered_set>
#include <iomanip>
#include <chrono>
#include <sstream>
#include <limits>
#include <functional>
using namespace std;
#define endl '\n'
// #define LOCAL

using int64 = int64_t;
using uint64 = unsigned long long;
using int128 = __int128_t;

#ifdef LOCAL
#include "src/debug.h"
#else
#define debug(...) 42
#endif

const int64 INF = numeric_limits<int64>::max();
int N, Q;
vector<int> W;

using Tag = int;     // -1 = ID, 0 = LEFT, 1 = RIGHT
static constexpr Tag ID = 0;
static constexpr Tag LEFT = -1;
static constexpr Tag RIGHT = 1;

struct Node {
    int64 len, left, right;
    int side;
};

Node NEUTRAL() { return Node{ -1, 0, INF, ID }; }

struct LazySegmentTree {
    vector<Node> arr;
    vector<Tag> lazyTag;
    int size;

    struct Configuration {
        const Node neutral; // neutral element for merge
        const Tag noop; // identity element for lazy
        function<Node(const Node&, const Node&)> merge; // combine two children
        function<Node(const Node&, Tag, int)> apply; // apply lazy tag to node value over length
        function<Tag(Tag, Tag)> compose; // merge two lazy tags
    } config;

    LazySegmentTree(int n, Configuration config) : config(config) { init(n); }

    void init(int n) {
        size = 1;
        while (size < n) size *= 2;
        arr.assign(2 * size, config.neutral);
        lazyTag.assign(2 * size, config.noop);
    }

    void build(const vector<Node>& inputArr) {
        copy(inputArr.begin(), inputArr.end(), arr.begin() + (size - 1));
        for (int i = size - 2; i >= 0; --i) {
            arr[i] = config.merge(arr[2 * i + 1], arr[2 * i + 2]);
        }
    }

    bool is_leaf(int segment_right_bound, int segment_left_bound) {
        return segment_right_bound - segment_left_bound == 1;
    }

    void push(int segment_idx, int segment_left_bound, int segment_right_bound) {
        bool pendingUpdate = lazyTag[segment_idx] != config.noop;
        if (is_leaf(segment_right_bound, segment_left_bound) || !pendingUpdate) return;
        int left_segment_idx = 2 * segment_idx + 1, right_segment_idx = 2 * segment_idx + 2;
        int children_segment_len = (segment_right_bound - segment_left_bound) >> 1;
        lazyTag[left_segment_idx] = config.compose(lazyTag[left_segment_idx], lazyTag[segment_idx]);
        lazyTag[right_segment_idx] = config.compose(lazyTag[right_segment_idx], lazyTag[segment_idx]);
        arr[left_segment_idx] = config.apply(arr[left_segment_idx], lazyTag[segment_idx], children_segment_len);
        arr[right_segment_idx] = config.apply(arr[right_segment_idx], lazyTag[segment_idx], children_segment_len);
        lazyTag[segment_idx] = config.noop;
    }

    void update(int left, int right, int64 val) {
        update(0, 0, size, left, right, val);
    }

    void update(int segment_idx, int segment_left_bound, int segment_right_bound, int left, int right, int64 val) {
        // NO OVERLAP
        if (right <= segment_left_bound || segment_right_bound <= left) return;
        // COMPLETE OVERLAP
        if (left <= segment_left_bound && segment_right_bound <= right) {
            lazyTag[segment_idx] = config.compose(lazyTag[segment_idx], val);
            int segment_len = segment_right_bound - segment_left_bound;
            arr[segment_idx] = config.apply(arr[segment_idx], val, segment_len);
            return;
        }
        // PARTIAL OVERLAP;
        push(segment_idx, segment_left_bound, segment_right_bound);
        int mid_point = (segment_left_bound + segment_right_bound) >> 1;
        int left_segment_idx = 2 * segment_idx + 1, right_segment_idx = 2 * segment_idx + 2;
        update(left_segment_idx, segment_left_bound, mid_point, left, right, val);
        update(right_segment_idx, mid_point, segment_right_bound, left, right, val);
        // pull
        arr[segment_idx] = config.merge(arr[left_segment_idx], arr[right_segment_idx]);
    }

    Node range_query(int left, int right) {
        return range_query(0, 0, size, left, right);
    }

    Node range_query(int segment_idx, int segment_left_bound, int segment_right_bound, int left, int right) {
        // NO OVERLAP
        if (right <= segment_left_bound || segment_right_bound <= left) return config.neutral;
        // COMPLETE OVERLAP
        if (left <= segment_left_bound && segment_right_bound <= right) {
            return arr[segment_idx];
        }
        // PARTIAL OVERLAP
        push(segment_idx, segment_left_bound, segment_right_bound);
        int mid_point = (segment_left_bound + segment_right_bound) >> 1;
        int left_segment_idx = 2 * segment_idx + 1, right_segment_idx = 2 * segment_idx + 2;
        Node left_res = range_query(left_segment_idx, segment_left_bound, mid_point, left, right);
        Node right_res = range_query(right_segment_idx, mid_point, segment_right_bound, left, right);
        return config.merge(left_res, right_res);
    }

    Node point_query(int i) { 
        return point_query(0, 0, size, i); 
    }

    Node point_query(int segment_idx, int l, int r, int i) {
        if (r - l == 1) return arr[segment_idx];
        push(segment_idx, l, r);// make children up to date
        int m = (l + r) >> 1;
        if (i < m) {
            return point_query(2 * segment_idx + 1, l, m, i);
        }
        return point_query(2 * segment_idx + 2, m, r, i);
    }

    // maxRight: largest r in [l, limit) such that pred(range_query(l, r)) is true.
    // If limit < 0 it defaults to the whole array size.
    // Precondition: pred(neutral) == true.
    template<class Pred>
    int maxRight(int l, Pred pred, int limit = -1) {
        if (limit < 0 || limit > size) limit = size;
        l = max(0, min(l, limit));
        // must hold on identity
        if (!pred(config.neutral)) return l; // or throw logic_error("pred(neutral) must be true");
        Node acc = config.neutral;
        return maxRightDfs(0, 0, size, l, limit, acc, pred);
    }
    template<class Pred>
    int maxRightDfs(int node, int nl, int nr, int ql, int limit, Node& acc, const Pred& pred) {
        // Node entirely left of ql, or entirely beyond the search limit
        if (nr <= ql || limit <= nl) return ql;

        // If we can take this whole node, do it greedily
        if (ql <= nl && nr <= limit) {
            Node combined = config.merge(acc, arr[node]);
            if (pred(combined)) { // ok to take all of it
                acc = combined;
                return nr;
            }
        }


        // If we cannot take it whole and it is a leaf, we stop here
        if (nr - nl == 1) return nl;

        // Otherwise we must split
        push(node, nl, nr);
        int mid = (nl + nr) >> 1;
        int left_segment_idx = 2 * node + 1, right_segment_idx = 2 * node + 2;

        // Try to take as much as possible from the left child
        int res = maxRightDfs(left_segment_idx, nl, mid, ql, limit, acc, pred);

        if (res < min(mid, limit)) return res; // boundary found inside left child
        // Then continue into the right child
        return maxRightDfs(right_segment_idx, mid, nr, res, limit, acc, pred);
    }

    void point_set(int i, Node newVal) {
        point_set(0, 0, size, i, newVal);
    }
    void point_set(int node, int nl, int nr, int i, Node newVal) {
        if (nr - nl == 1) {
            arr[node] = newVal;
            lazyTag[node] = config.noop; // leaf carries no pending work
            return;
        }
        push(node, nl, nr);
        int m = (nl + nr) >> 1;
        if (i < m) point_set(2*node + 1, nl, m, i, newVal);
        else       point_set(2*node + 2, m, nr, i, newVal);
        arr[node] = config.merge(arr[2*node + 1], arr[2*node + 2]); // pull
    }
};

LazySegmentTree::Configuration cfg{
    NEUTRAL(),
    ID,
    [](const Node& x, const Node& y) {
        if (x.len == -1) return y;
        if (y.len == -1) return x;
        Node z;
        z.len = x.len;
        z.side = y.side;
        if (x.side == LEFT) {
            z.left = x.left + y.left;
            z.right = x.left + y.right;
        } else {
            z.left = x.right - y.len + y.left;
            z.right = x.right - y.len + y.right;
        }
        return z;
    },
    [](const Node& x, Tag t, int /*seglen*/){ 
        if (t == ID || x.len == -1) return x;
        int64 width = x.right - x.left;
        if (t == LEFT) return Node{ x.len, 0, width, LEFT };
        else return Node{ x.len, x.len - width, x.len, RIGHT };
     },
    [](Tag oldTag, Tag newTag){ return newTag != ID ? newTag : oldTag; }
};

void solve() {
    cin >> N;
    W.resize(N);
    for (int i = 0; i < N; i++) {
        cin >> W[i];
    }
    reverse(W.begin(), W.end());
    LazySegmentTree seg(N, cfg);
    vector<Node> leaves(N);
    for (int i = 0; i < N; i++) {
        leaves[i] = Node{ W[i], 0, W[i], LEFT };
    }
    seg.build(leaves);
    cin >> Q;
    while (Q--) {
        int t, x;
        cin >> t >> x;
        if (t == 1) {
            // left
            seg.update(N - x, N, LEFT);
        } else if (t == 2) {
            // right
            seg.update(N - x, N, RIGHT);
        } else {
            // query
            auto pred = [&](const Node& node) {
                if (node.len == -1) return true;
                return x >= node.left && x < node.right;
            };
            int ans = seg.maxRight(0, pred, N);
            cout << ans << endl;
        }
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    solve();
    return 0;
}

Submission Info

Submission Time
Task F - Pyramid Alignment
User therealchainman
Language C++ 20 (gcc 12.2)
Score 525
Code Size 10051 Byte
Status AC
Exec Time 222 ms
Memory 28660 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 525 / 525
Status
AC × 1
AC × 16
Set Name Test Cases
Sample 00-sample-01.txt
All 00-sample-01.txt, 01-01.txt, 01-02.txt, 01-03.txt, 01-04.txt, 01-05.txt, 01-06.txt, 01-07.txt, 01-08.txt, 01-09.txt, 01-10.txt, 01-11.txt, 01-12.txt, max-01.txt, max-02.txt, max-03.txt
Case Name Status Exec Time Memory
00-sample-01.txt AC 1 ms 3380 KiB
01-01.txt AC 180 ms 27868 KiB
01-02.txt AC 156 ms 27156 KiB
01-03.txt AC 173 ms 16524 KiB
01-04.txt AC 132 ms 28528 KiB
01-05.txt AC 173 ms 28608 KiB
01-06.txt AC 203 ms 28600 KiB
01-07.txt AC 173 ms 28596 KiB
01-08.txt AC 130 ms 28404 KiB
01-09.txt AC 139 ms 28396 KiB
01-10.txt AC 141 ms 27608 KiB
01-11.txt AC 147 ms 28332 KiB
01-12.txt AC 156 ms 27608 KiB
max-01.txt AC 147 ms 28596 KiB
max-02.txt AC 222 ms 28660 KiB
max-03.txt AC 151 ms 28592 KiB