Submission #635257

#TimeUsernameProblemLanguageResultExecution timeMemory
635257phathnvRadio Towers (IOI22_towers)C++17
100 / 100
1507 ms96240 KiB
#include "towers.h"
 
#include <bits/stdc++.h>
using namespace std;
 
struct Node {
    Node* nLeft;
    Node* nRight;
    int l, r, sum, minPos, maxPos, minVal;
    Node(int _l, int _r, int val) {
        nLeft = nRight = nullptr;
        l = _l;
        r = _r;
        sum = 0;
        minPos = 1e9;
        maxPos = -1e9;
        minVal = val;
        assert(l <= r);
    }
};
 
Node* mergeNode(Node* a, Node* b) {
    assert(a->r + 1 == b->l);
    Node* res = new Node(a->l, b->r, 1e9);
    res->nLeft = a;
    res->nRight = b;
    res->sum = a->sum + b->sum;
    res->minPos = min(a->minPos, b->minPos);
    res->maxPos = max(a->maxPos, b->maxPos);
    res->minVal = min(a->minVal, b->minVal);
    return res;
}
 
Node* build(int l, int r, const vector<int>& h, const vector<bool>& mark) {
    if (l == r) {
        Node* n = new Node(l, r, h[l]);
        if (mark[l]) {
            n->sum = 1;
            n->minPos = n->maxPos = l;
        }
        return n;
    }
    int mid = (l + r) >> 1;
    return mergeNode(build(l, mid, h, mark), build(mid + 1, r, h, mark));
}
 
Node* update(Node* n, int pos) {
    if (pos < n->l || n->r < pos) {
        return n;
    }
    if (n->l == n->r) {
        assert(n->sum == 1);
        return new Node(n->l, n->r, n->minVal);
    }
    return mergeNode(update(n->nLeft, pos), update(n->nRight, pos));
}
 
int getMin(Node*n, int l, int r) {
    if (r < n->l || n->r < l) {
        return 1e9;
    }
    if (l <= n->l && n->r <= r) {
        return n->minVal;
    }
    return min(getMin(n->nLeft, l, r), getMin(n->nRight, l, r));
}
 
void get(Node*n, int l, int r, int &x, int &y, int &sum) {
    if (r < n->l || n->r < l) {
        return;
    }
    if (l <= n->l && n->r <= r) {
        sum += n->sum;
        x = min(x, n->minPos);
        y = max(y, n->maxPos);
        return;
    }
    get(n->nLeft, l, r, x, y, sum);
    get(n->nRight, l, r, x, y, sum);
}
 
int n;
vector<int> h;
vector<int> type, changingPoint;
vector<Node*> roots;
 
void init(int _n, vector<int> _h) {
    n = _n;
    h = _h;
 
    set<int> s;
    s.insert(0);
    for (int i = 1; i < n; ++i) {
        if (s.size() & 1) {
            if (h[i] > h[*s.rbegin()]) {
                s.insert(i);
            } else {
                s.erase(*s.rbegin());
                s.insert(i);
            }
        } else {
            if (h[i] < h[*s.rbegin()]) {
                s.insert(i);
            } else {
                s.erase(*s.rbegin());
                s.insert(i);
            }
        }
    }
    if (s.size() % 2 == 0) {
        s.erase(*s.rbegin());
    }
 
    vector<bool> mark(n, false);
    for (auto x : s) {
        mark[x] = true;
    }
    changingPoint.push_back(0);
    roots.push_back(build(0, n - 1, h, mark));
 
    priority_queue<array<int, 3>> pq;
    type.assign(n, -1);
    int pre = -1, t = 0;
    for (int cur : s) {
        type[cur] = t;
        t ^= 1;
        if (pre != -1) {
            pq.push({-abs(h[pre] - h[cur]), pre, cur});
        }
        pre = cur;
    }
 
    int last = 0;
    while (!pq.empty()) {
        auto [d, l, r] = pq.top();
        pq.pop();
        if (!mark[l] || !mark[r]) {
            continue;
        }
 
        d = -d;
        if (d != last) {
            changingPoint.push_back(d);
            roots.push_back(roots.back());
            last = d;
        }
 
        int a[5] = {-1, -1, -1, -1, -1};
 
        if (h[l] > h[r]) {
            a[1] = l;
            a[2] = r;
            auto it = s.lower_bound(l);
            if (it != s.begin()) {
                a[0] = *(--it);
            }
            it = s.lower_bound(r);
            ++it;
            if (it != s.end()) {
                a[3] = *it;
                ++it;
            }
            if (it != s.end()) {
                a[4] = *it;
                ++it;
            }
        } else {
            a[2] = l;
            a[3] = r;
            auto it = s.lower_bound(l);
            if (it != s.begin()) {
                a[1] = *(--it);
            }
            if (it != s.begin()) {
                a[0] = *(--it);
            }
            it = s.lower_bound(r);
            ++it;
            if (it != s.end()) {
                a[4] = *it;
                ++it;
            }
        }
 
        roots.back() = update(roots.back(), a[2]);
        mark[a[2]] = false;
        s.erase(a[2]);
        if (a[1] == -1 || a[3] == -1) {
            if (a[1] != -1) {
                roots.back() = update(roots.back(), a[1]);
                mark[a[1]] = false;
                s.erase(a[1]);
            }
            if (a[3] != -1) {
                roots.back() = update(roots.back(), a[3]);
                mark[a[3]] = false;
                s.erase(a[3]);
            }
        } else {
            if (h[a[1]] > h[a[3]]) {
                roots.back() = update(roots.back(), a[3]);
                mark[a[3]] = false;
                s.erase(a[3]);
                pq.push({-abs(h[a[1]] - h[a[4]]), a[1], a[4]});
            } else {
                roots.back() = update(roots.back(), a[1]);
                mark[a[1]] = false;
                s.erase(a[1]);
                pq.push({-abs(h[a[0]] - h[a[3]]), a[0], a[3]});
            }
        }
    }
}
 
int max_towers(int l, int r, int d) {
    Node* root = roots[lower_bound(changingPoint.begin(), changingPoint.end(), d) - changingPoint.begin() - 1];
 
    int x = 1e9, y = -1e9, res = 0;
    get(root, l, r, x, y, res);
 
    if (x > y) {
        return 1;
    }
 
    assert(type[x] != -1 && type[y] != -1);
 
    if (type[x] == 1) {
        if (h[x] - d >= getMin(root, l, x - 1)) {
            ++res;
        } else {
            --res;
        }
    }
    if (type[y] == 1) {
        if (h[y] - d >= getMin(root, y + 1, r)) {
            ++res;
        } else {
            --res;
        }
    }
    return max(1, (res + 1) / 2);
}
#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...