제출 #1339064

#제출 시각아이디문제언어결과실행 시간메모리
1339064madamadam3송신탑 (IOI22_towers)C++20
0 / 100
4065 ms7040 KiB
#include "towers.h"
#include <bits/stdc++.h>
using namespace std;

using vi = vector<int>;
using pi = pair<int,int>;

static const int INF = 1e9;

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 merge(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] = merge(build(p << 1, l, m), build(p << 1 | 1, m, r));
  }

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

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

struct PersistentRectCounter {
  struct InnerNode {
    int l = 0, r = 0, sum = 0;
  };
  struct OuterNode {
    int l = 0, r = 0, inner = 0;
  };
  struct Point {
    int key;   // active iff key >= D
    int x;     // first_left + 1
    int y;     // first_right
  };

  int M = 0;  // coordinates in [0, M)
  vector<InnerNode> in;
  vector<OuterNode> out;
  vector<int> vals;   // distinct keys, descending
  vector<int> roots;  // root for all points with key >= vals[i]

  PersistentRectCounter() {}

  int new_inner(int from) {
    in.push_back(in[from]);
    return (int)in.size() - 1;
  }

  int new_outer(int from) {
    out.push_back(out[from]);
    return (int)out.size() - 1;
  }

  int upd_inner(int node, int l, int r, int pos) {
    int u = new_inner(node);
    in[u].sum++;
    if (l + 1 == r) return u;
    int m = (l + r) >> 1;
    if (pos < m) in[u].l = upd_inner(in[u].l, l, m, pos);
    else         in[u].r = upd_inner(in[u].r, m, r, pos);
    return u;
  }

  int upd_outer(int node, int l, int r, int y, int x) {
    int u = new_outer(node);
    out[u].inner = upd_inner(out[u].inner, 0, M, x);
    if (l + 1 == r) return u;
    int m = (l + r) >> 1;
    if (y < m) out[u].l = upd_outer(out[u].l, l, m, y, x);
    else       out[u].r = upd_outer(out[u].r, m, r, y, x);
    return u;
  }

  int qry_inner(int node, int l, int r, int ql, int qr) const {
    if (!node || qr <= l || r <= ql) return 0;
    if (ql <= l && r <= qr) return in[node].sum;
    int m = (l + r) >> 1;
    return qry_inner(in[node].l, l, m, ql, qr) +
           qry_inner(in[node].r, m, r, ql, qr);
  }

  int qry_outer(int node, int l, int r, int qyl, int qyr, int qxl, int qxr) const {
    if (!node || qyr <= l || r <= qyl) return 0;
    if (qyl <= l && r <= qyr) {
      return qry_inner(out[node].inner, 0, M, qxl, qxr);
    }
    int m = (l + r) >> 1;
    return qry_outer(out[node].l, l, m, qyl, qyr, qxl, qxr) +
           qry_outer(out[node].r, m, r, qyl, qyr, qxl, qxr);
  }

  void init(int coord_size, vector<Point> pts) {
    M = coord_size;
    in.clear();
    out.clear();
    vals.clear();
    roots.clear();
    in.push_back({});
    out.push_back({});

    sort(pts.begin(), pts.end(), [&](const Point& a, const Point& b) {
      if (a.key != b.key) return a.key > b.key;
      if (a.y != b.y) return a.y < b.y;
      return a.x < b.x;
    });

    int cur = 0;
    for (int i = 0; i < (int)pts.size();) {
      int j = i;
      while (j < (int)pts.size() && pts[j].key == pts[i].key) {
        cur = upd_outer(cur, 0, M, pts[j].y, pts[j].x);
        j++;
      }
      vals.push_back(pts[i].key);
      roots.push_back(cur);
      i = j;
    }
  }

  int version_for_D(int D) const {
    int lo = 0, hi = (int)vals.size() - 1, ans = -1;
    while (lo <= hi) {
      int mid = (lo + hi) >> 1;
      if (vals[mid] >= D) {
        ans = mid;
        lo = mid + 1;
      } else {
        hi = mid - 1;
      }
    }
    return ans;
  }

  // count active points with x in [xl, xr), y in [yl, yr)
  int query(int D, int xl, int xr, int yl, int yr) const {
    if (xl >= xr || yl >= yr) return 0;
    int id = version_for_D(D);
    if (id == -1) return 0;
    return qry_outer(roots[id], 0, M, yl, yr, xl, xr);
  }
};

int n;
vi h, ord, first_left, first_right;
int delta_left[100000], delta_right[100000];
SegTree st;
bitset<100000> seen_fwd, seen_rev;

int rpos(int i) { return 100000 - i - 1; }

PersistentRectCounter ds_mid, ds_left, ds_right;

void init(int N, vector<int> H) {
  n = N;
  h = H;
  ord.resize(n);
  iota(ord.begin(), ord.end(), 0);
  sort(ord.begin(), ord.end(), [&](int a, int b) { return h[a] < h[b]; });

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

  seen_fwd.reset();
  seen_rev.reset();

  for (int i : ord) {
    int nxt = (int)seen_fwd._Find_next(i);
    int rev = (int)seen_rev._Find_next(rpos(i));
    int prv = (rev >= 100000 ? -1 : 100000 - 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]);

    seen_fwd.set(i);
    seen_rev.set(rpos(i));
  }

  vector<PersistentRectCounter::Point> p_mid, p_left, p_right;
  p_mid.reserve(n);
  p_left.reserve(n);
  p_right.reserve(n);

  for (int i = 0; i < n; i++) {
    int x = first_left[i] + 1;  // shift [-1..n-1] -> [0..n]
    int y = first_right[i];     // [0..n]

    p_mid.push_back({min(delta_left[i], delta_right[i]), x, y});
    p_left.push_back({delta_right[i], x, y});
    p_right.push_back({delta_left[i], x, y});
  }

  int M = n + 1;
  ds_mid.init(M, p_mid);
  ds_left.init(M, p_left);
  ds_right.init(M, p_right);
}

int max_towers(int L, int R, int D) {
  int ans = 1;

  // first_left[i] >= L && first_right[i] <= R && min(dl,dr) >= D
  // x = first_left+1 in [L+1, n+1), y = first_right in [0, R+1)
  ans += ds_mid.query(D, L + 1, n + 1, 0, R + 1);

  // first_left[i] < L && first_right[i] <= R && delta_right[i] >= D
  // x in [0, L), after shift becomes [0, L+1), y in [0, R+1)
  ans += ds_left.query(D, 0, L + 1, 0, R + 1);

  // first_left[i] >= L && first_right[i] > R && delta_left[i] >= D
  // x in [L+1, n+1), y in [R+1, n+1)
  ans += ds_right.query(D, L + 1, n + 1, R + 1, n + 1);

  return ans;
}
#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...