Submission #1317631

#TimeUsernameProblemLanguageResultExecution timeMemory
1317631madamadam3Obstacles for a Llama (IOI25_obstacles)C++20
58 / 100
2096 ms22260 KiB
#include "obstacles.h"
#include <bits/stdc++.h>

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

struct SegTree {
  int n; vi arr; vector<pi> st;
  SegTree() {}
  SegTree(int N, vi &Arr) {
    n = N; arr = Arr; st.assign(4*n, {-1, -1});
    build(0, 0, n);
  }

  pi combine(pi x, pi y) {
    pi r = {-1, -1};
    if (x.first < 0) r.first = y.first;
    else if (y.first < 0) r.first = x.first;
    else r.first = arr[x.first] < arr[y.first] ? x.first : y.first;
    
    if (x.second < 0) r.second = y.second;
    else if (y.second < 0) r.second = x.second;
    else r.second = arr[x.second] > arr[y.second] ? x.second : y.second;

    return r;
  }

  pi build(int i, int l, int r) {
    if (l+1==r) return st[i] = {l, l};
    int m = l + (r- l)/2;
    return st[i] = combine(build(2*i+1, l, m), build(2*i+2, m, r));
  }

  pi query(int i, int l, int r, int ql, int qr) {
    if (qr <= l || r <= ql) return {-1, -1};
    if (ql <= l && r <= qr) return st[i];

    int m = l + (r - l) / 2;
    return combine(query(2*i+1, l, m, ql, qr), query(2*i+2, m, r, ql, qr));
  }

  // max i in [l, r] such that max([l, i]) < T or min([l, i]) > T
  int right(int i, int l, int r, int ql, int qr, int T, bool mx) {
    if (r <= ql || qr <= l) return -1;
    if (ql <= l && r <= qr) {
      if ((mx && (st[i].second >= 0 && arr[st[i].second] < T)) || (!mx && (st[i].first >= 0 && arr[st[i].first] > T))) return -1;
    }

    if (l + 1 == r) return ((mx && arr[l] >= T) || (!mx && arr[l] <= T)) ? l : -1;

    int m = l + (r - l) / 2;
    int left = right(2*i+1, l, m, ql, qr, T, mx);
    if (left != -1) return left;
    return right(2*i+2, m, r, ql, qr, T, mx);
  }
  // min i in [l, r] such that max([i, r]) < T or min([i, r]) > T
  int left(int i, int l, int r, int ql, int qr, int T, bool mx) {
    if (r <= ql || qr <= l) return -1;
    if (ql <= l && r <= qr) {
      if ((mx && (st[i].second >= 0 && arr[st[i].second] < T)) || (!mx && (st[i].first >= 0 && arr[st[i].first] > T))) return -1;
    }

    if (l + 1 == r) return ((mx && arr[l] >= T) || (!mx && arr[l] <= T)) ? l : -1;

    int m = l + (r - l) / 2;
    int right = left(2*i+2, m, r, ql, qr, T, mx);
    if (right != -1) return right;
    return left(2*i+1, l, m, ql, qr, T, mx);
  }
};

int r, c;
SegTree row, col;
vi t, h;
void initialize(vi T, vi H) {
  r = T.size(); c = H.size();
  t = T; h = H;
  row = SegTree(r, T); col = SegTree(c, H);
  return;
}

bool can_reach(int L, int R, int s, int d) {
  if (s>d) swap(s, d);

  int mx = h[col.query(0, 0, c, s, d+1).second];
  int lo = 0, hi = r;
  while (lo < hi) {
    int mid = lo + (hi - lo) / 2;
    if (t[row.query(0, 0, r, 0, mid+1).second] > mx) hi = mid;
    else lo = mid + 1;
  }

  int first = lo;
  if (first >= r || t[first] <= mx) return false;

  auto get_range = [&](int i, int x, int ca, int cb) {
    // int lo1 = 0, hi1 = ca;
    // int lo2 = cb, hi2 = c;

    // while (lo1 < hi1) {
    //   int mid = lo1 + (hi1 - lo1) / 2;
    //   if (h[col.query(0, 0, c, mid, x+1).second] < t[i]) hi1 = mid;
    //   else lo1 = mid + 1;
    // }

    // while (lo2 < hi2) {
    //   int mid = lo2 + (hi2 - lo2) / 2;
    //   if (h[col.query(0, 0, c, x, mid+1).second] < t[i]) lo2 = mid+1;
    //   else hi2 = mid;
    // }
    // return make_pair(lo1, lo2-1);

    // int a = ca, b = cb;
    int a = col.left(0, 0, c, 0, ca+1, t[i], true), b = col.right(0, 0, c, cb, c, t[i], true);
    a = (a == -1) ? 0 : a+1; b = (b == -1) ? c-1 : b-1;
    // while (a > 0 && t[i] > h[a-1]) a--;
    // while (b < c-1 && t[i] > h[b+1] ) b++;
    return make_pair(a, b);
  };

  int ra = 0, rb = 0;
  int ca = s, cb = s, da = d, db = d;
  while (ra < first || rb < first) {
    if (ra < first) {
      s = col.query(0, 0, c, ca, cb+1).first;
      int posx = row.right(0, 0, r, ra, r, h[s], false);
      if (posx == -1) posx = r-1;

      if (posx == ra) return false;
      ra = posx;

      int maxy = row.query(0, 0, r, 0, posx+1).second;
      auto range = get_range(maxy, s, ca, cb);
      ca = range.first, cb = range.second;
    } 
    if (rb < first) {
      d = col.query(0, 0, c, da, db+1).first;
      int posx = row.right(0, 0, r, rb, r, h[d], false);
      if (posx == -1) posx = r-1;

      if (posx == rb) return false;
      rb = posx;

      int maxy = row.query(0, 0, r, 0, posx+1).second;
      auto range = get_range(maxy, d, da, db);
      da = range.first, db = range.second;
    } 
  }
  
  return true;
}
#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...