Submission #1339078

#TimeUsernameProblemLanguageResultExecution timeMemory
1339078madamadam3Radio Towers (IOI22_towers)C++20
44 / 100
4017 ms1767752 KiB
#include "towers.h"
#include <bits/stdc++.h>

using namespace std;

#define all(x) (x).begin(), (x).end()
using vi = vector<int>;
using pi = pair<int, int>;

struct SegTree {
  int n;
  vi arr;
  vector<pi> st;

  SegTree() {}
  SegTree(int n_, const vi& a) : n(n_), arr(a), st(4 * n_, {INT_MIN, INT_MAX}) {
    build(1, 0, n);
  }

  pi combine(pi a, pi b) { return {max(a.first, b.first), min(a.second, b.second)}; }

  pi build(int p, int l, int r) {
    if (l + 1 == r) return st[p] = {arr[l], arr[l]};
    int m = (l + r) >> 1;
    return st[p] = combine(build(p << 1, l, m), build(p << 1 | 1, m, r));
  }

  pi query2(int p, int l, int r, int ql, int qr) {
    if (qr <= l || r <= ql) return {INT_MIN, INT_MAX};
    if (ql <= l && r <= qr) return st[p];
    int m = (l + r) >> 1;
    return combine(query2(p << 1, l, m, ql, qr), query2(p << 1 | 1, m, r, ql, qr));
  }

  int query_max(int l, int r) {
    if (l >= r) return INT_MIN;
    return query2(1, 0, n, l, r).first;
  }
};

static const int MAXN = 100000;
static const int INF = 1000000000;

int n;
vi h, idx, first_left, first_right;
int delta_left[MAXN], delta_right[MAXN];
SegTree st;
bitset<100000> fwd_alive, rev_alive;

int rpos(int i) { return (int)rev_alive.size() - i - 1; }

struct Event {
  int y;
  int key;
  int w;
};

struct Wavelet {
  int lo, hi;
  vector<int> left_cnt;
  vector<int> pref_sum;
  Wavelet *lch = nullptr, *rch = nullptr;

  Wavelet() : lo(0), hi(-1) {}

  Wavelet(const vector<int>& vals, const vector<int>& ws, int lo_, int hi_) : lo(lo_), hi(hi_) {
    int m = (int)vals.size();
    left_cnt.resize(m + 1, 0);
    pref_sum.resize(m + 1, 0);
    for (int i = 0; i < m; i++) {
      pref_sum[i + 1] = pref_sum[i] + ws[i];
    }
    if (m == 0 || lo == hi) return;

    int mid = (lo + hi) >> 1;
    vector<int> lv, rv, lw, rw;
    lv.reserve(m);
    rv.reserve(m);
    lw.reserve(m);
    rw.reserve(m);

    for (int i = 0; i < m; i++) {
      bool go_left = vals[i] <= mid;
      left_cnt[i + 1] = left_cnt[i] + (go_left ? 1 : 0);
      if (go_left) {
        lv.push_back(vals[i]);
        lw.push_back(ws[i]);
      } else {
        rv.push_back(vals[i]);
        rw.push_back(ws[i]);
      }
    }

    if (!lv.empty()) lch = new Wavelet(lv, lw, lo, mid);
    if (!rv.empty()) rch = new Wavelet(rv, rw, mid + 1, hi);
  }

  int query_ge_prefix(int pos, int k) const {
    if (pos <= 0 || hi < k) return 0;
    if (lo >= k) return pref_sum[pos];
    if (lo == hi) return 0;

    int left_pos = left_cnt[pos];
    int right_pos = pos - left_pos;
    int ans = 0;
    if (lch) ans += lch->query_ge_prefix(left_pos, k);
    if (rch) ans += rch->query_ge_prefix(right_pos, k);
    return ans;
  }
};

struct XNode {
  vector<Event> raw;
  vector<int> ys;
  Wavelet* wt = nullptr;
};

vector<XNode> xs;
vi all_keys;
bool built = false;

void add_event_to_x(int p, int l, int r, int ql, int qr, int y, int key, int w) {
  if (qr <= l || r <= ql) return;
  if (ql <= l && r <= qr) {
    xs[p].raw.push_back({y, key, w});
    return;
  }
  int m = (l + r) >> 1;
  add_event_to_x(p << 1, l, m, ql, qr, y, key, w);
  add_event_to_x(p << 1 | 1, m, r, ql, qr, y, key, w);
}

void add_interval_rect(int x1, int x2, int y1, int y2, int key) {
  if (x1 > x2 || y1 > y2) return;
  add_event_to_x(1, 0, n, x1, x2 + 1, y1, key, +1);
  if (y2 + 1 < n) add_event_to_x(1, 0, n, x1, x2 + 1, y2 + 1, key, -1);
}

void build_node(int p) {
  auto& v = xs[p].raw;
  if (v.empty()) return;

  sort(all(v), [](const Event& a, const Event& b) {
    if (a.y != b.y) return a.y < b.y;
    if (a.key != b.key) return a.key < b.key;
    return a.w < b.w;
  });

  vector<int> vals, ws;
  vals.reserve(v.size());
  ws.reserve(v.size());
  xs[p].ys.reserve(v.size());

  for (auto& e : v) {
    xs[p].ys.push_back(e.y);
    vals.push_back(e.key);
    ws.push_back(e.w);
  }

  xs[p].wt = new Wavelet(vals, ws, 0, (int)all_keys.size() - 1);
}

void build_all_xnodes(int p, int l, int r) {
  build_node(p);
  if (l + 1 == r) return;
  int m = (l + r) >> 1;
  build_all_xnodes(p << 1, l, m);
  build_all_xnodes(p << 1 | 1, m, r);
}

int key_index_for_D(int D) {
  return (int)(lower_bound(all(all_keys), D) - all_keys.begin());
}

int query_point(int p, int l, int r, int x, int y, int key_lb) {
  int ans = 0;

  if (xs[p].wt) {
    int pos = (int)(upper_bound(all(xs[p].ys), y) - xs[p].ys.begin());
    if (key_lb < (int)all_keys.size()) ans += xs[p].wt->query_ge_prefix(pos, key_lb);
  }

  if (l + 1 == r) return ans;
  int m = (l + r) >> 1;
  if (x < m) ans += query_point(p << 1, l, m, x, y, key_lb);
  else       ans += query_point(p << 1 | 1, m, r, x, y, key_lb);
  return ans;
}

void build_everything() {
  if (built) return;
  built = true;

  fwd_alive.reset();
  rev_alive.reset();

  for (int i : idx) {
    int nxt = (int)fwd_alive._Find_next(i);
    int rev = (int)rev_alive._Find_next(rpos(i));
    int prv = (rev >= (int)rev_alive.size() ? -1 : (int)rev_alive.size() - rev - 1);

    first_left[i] = prv;
    first_right[i] = min(n, nxt);

    delta_left[i] = (prv < 0 ? INF : st.query_max(prv, i + 1) - h[i]);
    delta_right[i] = (nxt >= n ? INF : st.query_max(i, nxt + 1) - h[i]);

    fwd_alive.set(i);
    rev_alive.set(rpos(i));
  }

  vector<int> keys;
  keys.reserve(3 * n);
  for (int i = 0; i < n; i++) {
    keys.push_back(min(delta_left[i], delta_right[i]));
    keys.push_back(delta_left[i]);
    keys.push_back(delta_right[i]);
  }
  sort(all(keys));
  keys.erase(unique(all(keys)), keys.end());
  all_keys = keys;

  xs.assign(4 * max(1, n), {});

  for (int i = 0; i < n; i++) {
    int fl = first_left[i];
    int fr = first_right[i];

    // Condition 1:
    // fl >= L && fr <= R && min(dl,dr) >= D
    // Rectangle in (L,R): [0..fl] x [fr..n-1]
    if (fl >= 0 && fr < n) {
      int key = key_index_for_D(min(delta_left[i], delta_right[i]));
      add_interval_rect(0, fl, fr, n - 1, key);
    }

    // Condition 2:
    // i in [L,R], fl < L, fr <= R, delta_right >= D
    // Rectangle: [fl+1..i] x [fr..n-1]
    if (fr < n) {
      int x1 = fl + 1;
      int x2 = i;
      if (x1 <= x2) {
        int key = key_index_for_D(delta_right[i]);
        add_interval_rect(x1, x2, fr, n - 1, key);
      }
    }

    // Condition 3:
    // i in [L,R], fl >= L, fr > R, delta_left >= D
    // Rectangle: [0..fl] x [i..fr-1]
    if (fl >= 0) {
      int y1 = i;
      int y2 = fr - 1;
      if (y1 <= y2) {
        int key = key_index_for_D(delta_left[i]);
        add_interval_rect(0, fl, y1, y2, key);
      }
    }
  }

  build_all_xnodes(1, 0, n);
}

void init(int N, vi H) {
  n = N;
  h = H;
  idx.resize(n);
  iota(all(idx), 0);
  sort(all(idx), [&](int i, int j) { return h[i] < h[j]; });

  first_left.assign(n, -1);
  first_right.assign(n, n);
  st = SegTree(n, h);

  built = false;
  xs.clear();
  all_keys.clear();
}

int max_towers(int L, int R, int D) {
  build_everything();
  int k = key_index_for_D(D);
  if (k >= (int)all_keys.size()) return 1;
  return 1 + query_point(1, 0, n, L, R, k);
}
#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...