Submission #776200

#TimeUsernameProblemLanguageResultExecution timeMemory
776200SanguineChameleonRadio Towers (IOI22_towers)C++17
100 / 100
1471 ms126592 KiB
#include "towers.h" #include <bits/stdc++.h> using namespace std; struct node1 { pair<int, int> max_val, min_val; int max_diff, min_diff; node1(): max_val(make_pair(0, 0)), min_val(make_pair(0, 0)), max_diff(0), min_diff(0) {}; node1(pair<int, int> _max_val, pair<int, int> _min_val, int _max_diff, int _min_diff): max_val(_max_val), min_val(_min_val), max_diff(_max_diff), min_diff(_min_diff) {}; }; struct node2 { int cnt, min_pos, max_pos; node2 *left; node2 *right; node2(): cnt(0), min_pos(0), max_pos(0), left(nullptr), right(nullptr) {}; node2(int _cnt, int _min_pos, int _max_pos, node2 *_left, node2 *_right): cnt(_cnt), min_pos(_min_pos), max_pos(_max_pos), left(_left), right(_right) {}; }; const int inf = 1e9 + 20; const int maxN = 1e5 + 20; int H[maxN]; node1 tree1[maxN * 4]; int N; node1 merge1(node1 left, node1 right) { return node1(max(left.max_val, right.max_val), min(left.min_val, right.min_val), max(max(left.max_diff, right.max_diff), left.max_val.first - right.min_val.first), min(min(left.min_diff, right.min_diff), left.min_val.first - right.max_val.first)); } node2* merge2(node2 *left, node2 *right) { return new node2(left->cnt + right->cnt, min(left->min_pos, right->min_pos), max(left->max_pos, right->max_pos), left, right); } void build1(int id, int lt, int rt) { if (lt == rt) { tree1[id] = node1(make_pair(H[lt], lt), make_pair(H[lt], lt), 0, 0); return; } int mt = (lt + rt) / 2; build1(id * 2, lt, mt); build1(id * 2 + 1, mt + 1, rt); tree1[id] = merge1(tree1[id * 2], tree1[id * 2 + 1]); } node2* build2(int lt, int rt) { if (lt == rt) { return new node2(0, N + 1, 0, nullptr, nullptr); } int mt = (lt + rt) / 2; return new node2(0, N + 1, 0, build2(lt, mt), build2(mt + 1, rt)); } node2* update2(node2 *cur, int lt, int rt, int pos) { if (lt == rt) { return new node2(1, pos, pos, nullptr, nullptr); } int mt = (lt + rt) / 2; if (pos <= mt) { return merge2(update2(cur->left, lt, mt, pos), cur->right); } else { return merge2(cur->left, update2(cur->right, mt + 1, rt, pos)); } } node2* get2(node2 *cur, int lt, int rt, int ql, int qr) { if (lt == ql && rt == qr) { return cur; } int mt = (lt + rt) / 2; if (qr <= mt) { return get2(cur->left, lt, mt, ql, qr); } else if (ql >= mt + 1) { return get2(cur->right, mt + 1, rt, ql, qr); } else { return merge2(get2(cur->left, lt, mt, ql, mt), get2(cur->right, mt + 1, rt, mt + 1, qr)); } } int _get_firstL(int id, int lt, int rt, int pos, int low) { if (lt == rt) { return lt - (H[lt] < low); } if (tree1[id].max_val.first < low) { return lt - 1; } int mt = (lt + rt) / 2; if (pos <= mt) { return _get_firstL(id * 2, lt, mt, pos, low); } else { int res = _get_firstL(id * 2 + 1, mt + 1, rt, pos, low); return (res >= mt + 1 ? res : _get_firstL(id * 2, lt, mt, pos, low)); } } int _get_firstR(int id, int lt, int rt, int pos, int low) { if (lt == rt) { return rt + (H[rt] < low); } if (tree1[id].max_val.first < low) { return rt + 1; } int mt = (lt + rt) / 2; if (pos >= mt + 1) { return _get_firstR(id * 2 + 1, mt + 1, rt, pos, low); } else { int res = _get_firstR(id * 2, lt, mt, pos, low); return (res <= mt ? res : _get_firstR(id * 2 + 1, mt + 1, rt, pos, low)); } } node1 get1(int id, int lt, int rt, int ql, int qr) { if (lt == ql && rt == qr) { return tree1[id]; } int mt = (lt + rt) / 2; if (qr <= mt) { return get1(id * 2, lt, mt, ql, qr); } else if (ql >= mt + 1) { return get1(id * 2 + 1, mt + 1, rt, ql, qr); } else { return merge1(get1(id * 2, lt, mt, ql, mt), get1(id * 2 + 1, mt + 1, rt, mt + 1, qr)); } } int get_firstL(int pos, int D) { return _get_firstL(1, 1, N, pos, H[pos] + D); } int get_firstR(int pos, int D) { return _get_firstR(1, 1, N, pos, H[pos] + D); } bool checkL(int pos, int D, int L) { int firstL = get_firstL(pos, D); if (firstL <= L) { return false; } auto left = get1(1, 1, N, L, firstL - 1); auto right = get1(1, 1, N, firstL, pos); return (left.min_diff <= -D) || (right.max_val.first - left.min_val.first >= D); } bool checkR(int pos, int D, int R) { int firstR = get_firstR(pos, D); if (firstR >= R) { return false; } auto right = get1(1, 1, N, firstR + 1, R); auto left = get1(1, 1, N, pos, firstR); return (right.max_diff >= D) || (left.max_val.first - right.min_val.first >= D); } vector<int> dists; vector<int> add; vector<node2*> roots; void init(int _N, vector<int> _H) { if (_N <= 2) { return; } N = _N; for (int i = 1; i <= N; i++) { H[i] = _H[i - 1]; } build1(1, 1, N); vector<int> extr; if (H[1] < H[2]) { extr.push_back(1); } for (int i = 2; i <= N - 1; i++) { if ((H[i - 1] < H[i]) ^ (H[i] < H[i + 1])) { extr.push_back(i); } } if (H[N - 1] > H[N]) { extr.push_back(N); } set<int> S(extr.begin(), extr.end()); priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<pair<int, pair<int, int>>>> Q; for (int i = 1; i < (int)extr.size(); i++) { Q.emplace(abs(H[extr[i - 1]] - H[extr[i]]), make_pair(extr[i - 1], extr[i])); } while (!Q.empty()) { int dist = Q.top().first; int X = Q.top().second.first; int Y = Q.top().second.second; Q.pop(); auto it = S.find(X); if (it == S.end() || next(it) == S.end() || *next(it) != Y) { continue; } dists.push_back(dist); add.push_back(H[X] < H[Y] ? X : Y); it = S.erase(it); it = S.erase(it); if (it != S.begin() && it != S.end()) { int prv = *prev(it); int nxt = *it; Q.emplace(abs(H[prv] - H[nxt]), make_pair(prv, nxt)); } } dists.push_back(inf); add.push_back(*S.begin()); roots.resize((int)dists.size() + 1); roots.back() = build2(1, N); for (int i = (int)roots.size() - 2; i >= 0; i--) { roots[i] = update2(roots[i + 1], 1, N, add[i]); } } int max_towers(int L, int R, int D) { L++; R++; if (R - L <= 1) { return 1; } node2 *range = get2(roots[lower_bound(dists.begin(), dists.end(), D) - dists.begin()], 1, N, L, R); if (!range->cnt) { int pos = get1(1, 1, N, L, R).min_val.second; return 1 + (checkL(pos, D, L) || checkR(pos, D, R)); } else { return range->cnt + checkL(range->min_pos, D, L) + checkR(range->max_pos, D, R); } }
#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...