Submission #1057140

#TimeUsernameProblemLanguageResultExecution timeMemory
1057140arbuzickComparing Plants (IOI20_plants)C++17
100 / 100
884 ms220808 KiB
#include "plants.h" #include <bits/stdc++.h> using namespace std; int n, k; constexpr int R = 1 << 18; int blocked[R * 2]; pair<int, int> mn[R * 2]; pair<int, int> mn_free[R * 2]; int add[R * 2]; void build() { for (int i = 0; i < R; ++i) { mn[i + R] = mn_free[i + R] = make_pair(0, i); } for (int i = R - 1; i > 0; --i) { mn[i] = mn_free[i] = min(mn[i * 2], mn[i * 2 + 1]); } } void push(int node) { if (add[node] != 0) { mn[node * 2].first += add[node]; mn_free[node * 2].first += add[node]; add[node * 2] += add[node]; mn[node * 2 + 1].first += add[node]; mn_free[node * 2 + 1].first += add[node]; add[node * 2 + 1] += add[node]; } add[node] = 0; } void add_blocked(int ql, int qr, int val, int node = 1, int nl = 0, int nr = R) { if (ql <= nl && nr <= qr) { blocked[node] += val; if (blocked[node] == 0) { if (nl == nr - 1) { mn_free[node] = mn[node]; } else { push(node); mn[node] = min(mn[node * 2], mn[node * 2 + 1]); mn_free[node] = min(mn_free[node * 2], mn_free[node * 2 + 1]); } } else { mn_free[node] = make_pair(R, -1); } return; } if (qr <= nl || nr <= ql) { return; } push(node); int nm = (nl + nr) / 2; add_blocked(ql, qr, val, node * 2, nl, nm); add_blocked(ql, qr, val, node * 2 + 1, nm, nr); mn[node] = min(mn[node * 2], mn[node * 2 + 1]); if (blocked[node] == 0) { mn_free[node] = min(mn_free[node * 2], mn_free[node * 2 + 1]); } } void add_val(int ql, int qr, int val, int node = 1, int nl = 0, int nr = R) { if (ql <= nl && nr <= qr) { mn[node].first += val; mn_free[node].first += val; add[node] += val; return; } if (qr <= nl || nr <= ql) { return; } push(node); int nm = (nl + nr) / 2; add_val(ql, qr, val, node * 2, nl, nm); add_val(ql, qr, val, node * 2 + 1, nm, nr); mn[node] = min(mn[node * 2], mn[node * 2 + 1]); if (blocked[node] == 0) { mn_free[node] = min(mn_free[node * 2], mn_free[node * 2 + 1]); } } int get_free_zero(int node = 1, int nl = 0, int nr = R) { if (blocked[node]) { return -1; } // cout << nl << ' ' << nr << ' ' << mn[node].first << endl; if (mn_free[node].first != 0) { return -1; } if (nl == nr - 1) { return mn[node].second; } push(node); int nm = (nl + nr) / 2; int ans = get_free_zero(node * 2, nl, nm); if (ans == -1) { ans = get_free_zero(node * 2 + 1, nm, nr); } mn[node] = min(mn[node * 2], mn[node * 2 + 1]); mn_free[node] = min(mn_free[node * 2], mn_free[node * 2 + 1]); return ans; } void get_all_zero(int ql, int qr, vector<int> &ans, int node = 1, int nl = 0, int nr = R) { if (mn[node].first != 0) { return; } if (qr <= nl || nr <= ql) { return; } if (nl == nr - 1) { ans.push_back(mn[node].second); return; } push(node); int nm = (nl + nr) / 2; get_all_zero(ql, qr, ans, node * 2, nl, nm); get_all_zero(ql, qr, ans, node * 2 + 1, nm, nr); mn[node] = min(mn[node * 2], mn[node * 2 + 1]); if (blocked[node] == 0) { mn_free[node] = min(mn_free[node * 2], mn_free[node * 2 + 1]); } } constexpr int R2 = 1 << 20; int mx[R2 * 2]; void build_mx() { for (int i = 1; i < R2 * 2; ++i) { mx[i] = -1; } } void _change(int pos, int val) { for (pos += R2; pos > 0; pos /= 2) { mx[pos] = max(mx[pos], val); } } void change(int pos, int val) { _change(pos, val); _change(pos + n, val); _change(pos + n * 2, val); } int _get(int l, int r) { l = max(0, l); r = min(R2, r); l += R2; r += R2; int ans = -1; while (l < r) { if (l & 1) { ans = max(ans, mx[l++]); } if (r & 1) { ans = max(ans, mx[--r]); } l >>= 1; r >>= 1; } return ans; } int get(int l, int r) { return _get(l + n, r + n); } constexpr int maxn = 2e5 + 5, lg = 20; vector<int> ord; int pos[maxn]; pair<pair<int, int>, int> go_left[lg][maxn][2], go_right[lg][maxn][2]; int prv_left[maxn][2], prv_right[maxn][2]; void init(int _k, vector<int> r) { n = r.size(); k = _k; build(); add_blocked(n, R, 1); for (int i = 0; i < n; ++i) { if (r[i] == 0) { if (i + k <= n) { add_blocked(i + 1, i + k, 1); } else { add_blocked(i + 1, n, 1); add_blocked(0, (i + k) % n, 1); } } add_val(i, i + 1, r[i]); } for (int _ = 0; _ < n; ++_) { int pos_mx = get_free_zero(); // cout << pos_mx << endl; ord.push_back(pos_mx); vector<int> new_zero; if (pos_mx >= k - 1) { add_val(pos_mx - k + 1, pos_mx, -1); get_all_zero(pos_mx - k + 1, pos_mx, new_zero); } else { if (pos_mx > 0) { add_val(0, pos_mx, -1); get_all_zero(0, pos_mx, new_zero); } add_val(n - (k - pos_mx) + 1, n, -1); get_all_zero(n - (k - pos_mx) + 1, n, new_zero); } if (pos_mx + k <= n) { add_blocked(pos_mx + 1, pos_mx + k, -1); } else { add_blocked(pos_mx + 1, n, -1); add_blocked(0, (pos_mx + k) % n, -1); } add_val(pos_mx, pos_mx + 1, R); // cout << pos_mx << ' ' << new_zero.size() << endl; for (auto pos : new_zero) { if (pos + k <= n) { add_blocked(pos + 1, pos + k, 1); } else { add_blocked(pos + 1, n, 1); add_blocked(0, (pos + k) % n, 1); } } } reverse(ord.begin(), ord.end()); build_mx(); for (int i = 0; i < n; ++i) { prv_left[i][0] = get(ord[i] - k + 1, ord[i]); prv_left[i][1] = get(ord[i] - k + 1 - n, ord[i] - n); prv_right[i][0] = get(ord[i] + 1, ord[i] + k); prv_right[i][1] = get(ord[i] + 1 + n, ord[i] + k + n); change(ord[i], i); if (prv_left[i][0] != -1) { if (ord[i] - k < ord[prv_left[i][0]] && ord[prv_left[i][0]] < ord[i]) { go_left[0][i][0] = make_pair(make_pair(prv_left[i][0], 0), ord[prv_left[i][0]] - k); } else { go_left[0][i][0] = make_pair(make_pair(prv_left[i][0], 1), ord[prv_left[i][0]] - k - n); } } else { go_left[0][i][0] = make_pair(make_pair(-1, -1), R); } if (prv_left[i][1] != -1) { go_left[0][i][1] = make_pair(make_pair(prv_left[i][1], 1), ord[prv_left[i][1]] - k - n); } else { go_left[0][i][1] = make_pair(make_pair(-1, -1), R); } if (prv_right[i][0] != -1) { if (ord[i] < ord[prv_right[i][0]] && ord[prv_right[i][0]] < ord[i] + k) { go_right[0][i][0] = make_pair(make_pair(prv_right[i][0], 0), ord[prv_right[i][0]] + k); } else { go_right[0][i][0] = make_pair(make_pair(prv_right[i][0], 1), ord[prv_right[i][0]] + k + n); } } else { go_right[0][i][0] = make_pair(make_pair(-1, -1), -R); } if (prv_right[i][1] != -1) { go_right[0][i][1] = make_pair(make_pair(prv_right[i][1], 1), ord[prv_right[i][1]] + k + n); } else { go_right[0][i][1] = make_pair(make_pair(-1, -1), -R); } } for (int i = 1; i < lg; ++i) { for (int j = 0; j < n; ++j) { for (int k = 0; k < 2; ++k) { if (go_left[i - 1][j][k].first.first != -1 && go_left[i - 1][go_left[i - 1][j][k].first.first][go_left[i - 1][j][k].first.second].first.first != -1) { go_left[i][j][k].first.first = go_left[i - 1][go_left[i - 1][j][k].first.first][go_left[i - 1][j][k].first.second].first.first; go_left[i][j][k].first.second = go_left[i - 1][go_left[i - 1][j][k].first.first][go_left[i - 1][j][k].first.second].first.second; go_left[i][j][k].second = min(go_left[i - 1][j][k].second, go_left[i - 1][go_left[i - 1][j][k].first.first][go_left[i - 1][j][k].first.second].second); } else { go_left[i][j][k] = make_pair(make_pair(-1, -1), R); } if (go_right[i - 1][j][k].first.first != -1 && go_right[i - 1][go_right[i - 1][j][k].first.first][go_right[i - 1][j][k].first.second].first.first != -1) { go_right[i][j][k].first.first = go_right[i - 1][go_right[i - 1][j][k].first.first][go_right[i - 1][j][k].first.second].first.first; go_right[i][j][k].first.second = go_right[i - 1][go_right[i - 1][j][k].first.first][go_right[i - 1][j][k].first.second].first.second; go_right[i][j][k].second = max(go_right[i - 1][j][k].second, go_right[i - 1][go_right[i - 1][j][k].first.first][go_right[i - 1][j][k].first.second].second); } else { go_right[i][j][k] = make_pair(make_pair(-1, -1), -R); } } } } for (int i = 0; i < n; ++i) { pos[ord[i]] = i; } } int compare_plants(int x, int y) { if (pos[x] > pos[y]) { int l = x - k, r = x + k; int nw1 = pos[x], nw2 = 0; for (int i = lg - 1; i >= 0; --i) { if (go_left[i][nw1][nw2].first.first > pos[y]) { l = min(l, go_left[i][nw1][nw2].second); int nw3 = go_left[i][nw1][nw2].first.first, nw4 = go_left[i][nw1][nw2].first.second; nw1 = nw3, nw2 = nw4; } } nw1 = pos[x], nw2 = 0; for (int i = lg - 1; i >= 0; --i) { if (go_right[i][nw1][nw2].first.first > pos[y]) { r = max(r, go_right[i][nw1][nw2].second); int nw3 = go_right[i][nw1][nw2].first.first, nw4 = go_right[i][nw1][nw2].first.second; nw1 = nw3, nw2 = nw4; } } if ((l < y && y < r) || (l < y - n && y - n < r) || (l < y + n && y + n < r)) { return 1; } return 0; } else { swap(x, y); int l = x - k, r = x + k; int nw1 = pos[x], nw2 = 0; for (int i = lg - 1; i >= 0; --i) { if (go_left[i][nw1][nw2].first.first > pos[y]) { l = min(l, go_left[i][nw1][nw2].second); int nw3 = go_left[i][nw1][nw2].first.first, nw4 = go_left[i][nw1][nw2].first.second; nw1 = nw3, nw2 = nw4; } } nw1 = pos[x], nw2 = 0; for (int i = lg - 1; i >= 0; --i) { if (go_right[i][nw1][nw2].first.first > pos[y]) { r = max(r, go_right[i][nw1][nw2].second); int nw3 = go_right[i][nw1][nw2].first.first, nw4 = go_right[i][nw1][nw2].first.second; nw1 = nw3, nw2 = nw4; } } if ((l < y && y < r) || (l < y - n && y - n < r) || (l < y + n && y + n < r)) { return -1; } return 0; } }
#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...