This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include "plants.h"
#include <bits/stdc++.h>
namespace {
class plants_solver {
struct index_data {
int l_to_r;
int l_to_r_2;
int r_to_l;
int r_to_l_2;
};
std::vector<index_data> v;
public:
plants_solver() { }
plants_solver(int N, int K, std::vector<int> R) : v(N) {
using std::min;
using std::max;
assert(N == int(R.size()));
assert(1 <= K && K <= N);
for (int& r : R) assert(0 <= r && r < K);
struct seg_node {
int val;
int ind;
int lazy;
int last_taken;
};
std::vector<seg_node> seg(2*N);
auto update_node = [&](int a) {
assert(a < N);
if (seg[2*a].val < seg[2*a+1].val) {
seg[a].val = seg[2*a].val;
seg[a].ind = seg[2*a].ind;
} else {
seg[a].val = seg[2*a+1].val;
seg[a].ind = seg[2*a+1].ind;
}
seg[a].val += seg[a].lazy;
seg[a].last_taken = max(seg[2*a].last_taken, seg[2*a+1].last_taken);
};
for (int i = 0; i < N; i++) {
seg[N+i] = seg_node{R[i], i, 0, -1};
}
for (int a = N-1; a; a--) update_node(a);
auto downdate_all = [&](int n) {
n >>= __builtin_ctz(n); n >>= 1;
if (!n) return;
for (int l = 31 - __builtin_clz(n); l >= 0; l--) {
int a = n >> l;
assert(a < N);
seg[2*a].val += seg[a].lazy;
seg[2*a].lazy += seg[a].lazy;
seg[2*a+1].val += seg[a].lazy;
seg[2*a+1].lazy += seg[a].lazy;
seg[a].lazy = 0;
}
};
std::vector<int> toposort; toposort.reserve(N);
std::vector<int> stk; stk.reserve(N);
std::vector<int> prev_bigger(N);
std::vector<int> next_bigger(N);
while (int(toposort.size()) < N) {
if (stk.empty()) {
assert(seg[1].val == 0);
stk.push_back(seg[1].ind);
}
int cur = stk.back();
//std::cerr << "trying " << cur << '\n';
int prev_taken = -1;
int lo = cur-(K-1), hi = cur;
if (lo < 0) {
lo += 2 * N, hi = 2 * (N + hi);
} else {
lo += N, hi += N;
}
downdate_all(lo);
downdate_all(hi);
int zero_ind = -1;
for (int a = lo, b = hi; a < b; a >>= 1, b >>= 1) {
if (a & 1) {
if (seg[a].val == 0) {
zero_ind = seg[a].ind;
goto found_zero;
}
prev_taken = max(prev_taken, seg[a].last_taken);
a++;
}
if (b & 1) {
--b;
if (seg[b].val == 0) {
zero_ind = seg[b].ind;
goto found_zero;
}
prev_taken = max(prev_taken, seg[b].last_taken);
}
}
goto not_found_zero;
found_zero:
{
//std::cerr << "bad: " << zero_ind << '\n';
stk.push_back(zero_ind);
continue;
}
not_found_zero:;
int next_taken = -1;
{
int lo2 = cur+1, hi2 = cur+K;
assert(lo2 <= N);
lo2 += N;
if (hi2 > N) {
hi2 = 2 * hi2;
} else {
hi2 += N;
}
for (int a = lo2, b = hi2; a < b; a >>= 1, b >>= 1) {
if (a & 1) {
next_taken = max(next_taken, seg[a].last_taken);
a++;
}
if (b & 1) {
--b;
next_taken = max(next_taken, seg[b].last_taken);
}
}
}
assert(stk.back() == cur);
stk.pop_back();
int t = int(toposort.size());
toposort.push_back(cur);
prev_bigger[cur] = (prev_taken == -1) ? -1 : toposort[prev_taken];
next_bigger[cur] = (next_taken == -1) ? -1 : toposort[next_taken];
//std::cerr << "take " << cur << ' ' << prev_bigger[cur] << ' ' << next_bigger[cur] << '\n';
seg[N+cur].last_taken = t;
seg[N+cur].val += K; // should never be bad
for (int a = lo, b = hi; a < b; a >>= 1, b >>= 1) {
if (a & 1) {
seg[a].lazy--;
seg[a].val--;
a++;
}
if (b & 1) {
--b;
seg[b].lazy--;
seg[b].val--;
}
}
for (int a = (N+cur) >> 1; a; a >>= 1) update_node(a);
for (int a = lo >> __builtin_ctz(lo) >> 1; a; a >>= 1) update_node(a);
}
{
std::vector<int> pred(2*N+1, -1);
{
int cur = 2*N;
for (int a : toposort) {
if (a > N-K) {
pred[cur] = N+a;
cur = N+a;
}
}
}
for (int i = 2*N-K; i >= 0; i--) {
assert(i + K <= 2 * N);
int j = next_bigger[i >= N ? i-N : i];
if (j == -1) {
j = 2 * N;
} else {
if (j < i) j += N;
assert(i < j && j < i + K);
}
pred[i] = pred[j];
pred[j] = i;
}
for (int cur = pred[2*N], idx = 2*N-1; idx >= 0; cur = pred[cur], idx--) {
if (cur >= N) {
v[cur - N].l_to_r_2 = idx;
} else {
v[cur].l_to_r = idx;
}
}
}
for (int i = 0; i < N; i++) {
//std::cerr << v[i].l_to_r << ' ' << v[i].l_to_r_2 << '\n';
assert(v[i].l_to_r > v[i].l_to_r_2);
}
{
std::vector<int> pred(2*N+1, -1);
{
int cur = 2 * N;
for (int a : toposort) {
if (a < K) {
pred[cur] = a;
cur = a;
}
}
}
for (int i = K; i < 2*N; i++) {
int j = prev_bigger[i >= N ? i-N : i];
if (j == -1) {
j = 2 * N;
} else {
if (j + N < i) {
j += N;
}
assert(i - K < j && j < i);
}
pred[i] = pred[j];
pred[j] = i;
}
for (int cur = pred[2*N], idx = 2*N-1; idx >= 0; cur = pred[cur], idx--) {
if (cur >= N) {
v[cur - N].r_to_l_2 = idx;
} else {
v[cur].r_to_l = idx;
}
}
}
for (int i = 0; i < N; i++) {
//std::cerr << v[i].r_to_l << ' ' << v[i].r_to_l_2 << '\n';
assert(v[i].r_to_l_2 > v[i].r_to_l);
}
}
public:
int compare_plants(int x, int y) const {
if (x == y) return 0;
if (x > y) {
return -compare_plants(y, x);
}
assert(x < y);
const auto& a = v[x];
const auto& b = v[y];
if (a.l_to_r < b.l_to_r) {
return -1;
}
if (b.l_to_r < a.l_to_r_2) {
return 1;
}
if (a.r_to_l_2 < b.r_to_l) {
return -1;
}
if (b.r_to_l < a.r_to_l) {
return 1;
}
return 0;
}
} SOLVER;
}
void init(int K, std::vector<int> R) {
int N = int(R.size());
SOLVER = plants_solver(N, K, R);
}
int compare_plants(int x, int y) {
return SOLVER.compare_plants(x, y);
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |