Submission #1358950

#TimeUsernameProblemLanguageResultExecution timeMemory
1358950avighnaBitaro's travel (JOI23_travel)C++20
100 / 100
1014 ms22208 KiB
#include <bits/stdc++.h>

using namespace std;

// lazy propagation only works for the alive/dead tree. assumes operation is +, not min
template <typename T, typename Fn>
class lazy_segment_tree {
  int n;
  vector<T> seg, lazy;

  Fn merge;
  T idt;

  void push(int v, int tl, int tr) {
    if (lazy[v] == -1) return;
    seg[v] = lazy[v] * (tr - tl + 1);
    if (v < 2 * n) {
      lazy[2 * v] = lazy[v];
      lazy[2 * v + 1] = lazy[v];
    }
    lazy[v] = -1;
  }

  void pull(int v) { seg[v] = merge(seg[2 * v], seg[2 * v + 1]); }

  void set(int v, int tl, int tr, int l, int r, int x) {
    push(v, tl, tr);
    if (tr < l || r < tl) return;
    if (l <= tl && tr <= r) {
      lazy[v] = x;
      push(v, tl, tr);
      return;
    }
    int tm = (tl + tr) / 2;
    set(2 * v, tl, tm, l, r, x);
    set(2 * v + 1, tm + 1, tr, l, r, x);
    pull(v);
  }

  T query(int v, int tl, int tr, int l, int r) {
    push(v, tl, tr);
    if (tr < l || r < tl) return idt;
    if (l <= tl && tr <= r) return seg[v];
    int tm = (tl + tr) / 2;
    return merge(query(2 * v, tl, tm, l, r), query(2 * v + 1, tm + 1, tr, l, r));
  }

  template <typename ChkFn>
  int min_left(int v, int tl, int tr, int l, const ChkFn &f) {
    push(v, tl, tr);
    if (tl > tr || tr < l || !f(seg[v])) return n;
    if (tl == tr) return tl;
    int tm = (tl + tr) / 2;
    int ans = min_left(2 * v, tl, tm, l, f);
    if (ans != n) return ans;
    return min_left(2 * v + 1, tm + 1, tr, l, f);
  }

  template <typename ChkFn>
  int max_right(int v, int tl, int tr, int r, const ChkFn &f) {
    push(v, tl, tr);
    if (tl > tr || r < tl || !f(seg[v])) return -1;
    if (tl == tr) return tl;
    int tm = (tl + tr) / 2;
    int ans = max_right(2 * v + 1, tm + 1, tr, r, f);
    if (ans != -1) return ans;
    return max_right(2 * v, tl, tm, r, f);
  }

public:
  lazy_segment_tree(int n, const Fn &merge, T idt) : n(n), merge(merge), idt(idt), seg(4 * n, idt), lazy(4 * n, -1) {}

  void set(int l, int r, int del) { set(1, 0, n - 1, l, r, del); }
  T query(int l, int r) { return query(1, 0, n - 1, l, r); }
  template <typename ChkFn>
  int min_left(int l, const ChkFn &f) { return min_left(1, 0, n - 1, l, f); }
  template <typename ChkFn>
  int max_right(int r, const ChkFn &f) { return max_right(1, 0, n - 1, r, f); }
};

const int inf = int(1e9) + 10;

int main() {
  cin.tie(nullptr)->sync_with_stdio(false);

  int n;
  cin >> n;
  vector<int> a(n);
  for (int &i : a) {
    cin >> i;
  }
  auto add_merge = [&](int a, int b) { return a + b; };
  lazy_segment_tree<int, decltype(add_merge)> alive(n, add_merge, 0);

  auto max_fn = [&](int a, int b) { return max(a, b); };
  lazy_segment_tree<int, decltype(max_fn)> st_left(n - 1, max_fn, -inf);
  lazy_segment_tree<int, decltype(max_fn)> st_right(n, max_fn, -inf);
  for (int i = 0; i < n - 1; ++i) {
    st_left.set(i, i, a[i + 1] - a[i]);
    st_right.set(i + 1, i + 1, a[i + 1] - a[i]);
  }

  int q;
  cin >> q;
  while (q--) {
    int64_t ans = 0;
    int x;
    cin >> x;
    if (n == 1) {
      cout << abs(a[0] - x) << '\n';
      continue;
    }
    alive.set(0, n - 1, 1); // initially everyone is alive

    // if we picked one of the initial spots, mark it as dead
    int idx = lower_bound(a.begin(), a.end(), x) - a.begin();
    if (idx != n && a[idx] == x) {
      alive.set(idx, idx, 0); // dead
    }

    auto mark_dead = [&](int l, int r) {
      if (l > r) return;
      auto it1 = lower_bound(a.begin(), a.end(), l);
      auto it2 = upper_bound(a.begin(), a.end(), r);
      if (it1 == a.end() || it2 == a.begin()) return;
      alive.set(it1 - a.begin(), it2 - a.begin() - 1, 0);
    };

    int sep = 0;
    auto go_left = [&]() {
      int l = alive.max_right(idx - 1, [&](int sum) { return sum > 0; });
      int idx = st_left.max_right(l - 1, [&](int val) { return val > sep; }) + 1;
      ans += x - a[idx];
      mark_dead(a[idx], x - 1);
      x = a[idx];
    };

    auto go_right = [&]() {
      int r = alive.min_left(idx, [&](int sum) { return sum > 0; });
      int idx = st_right.min_left(r + 1, [&](int val) { return val > sep; }) - 1;
      ans += a[idx] - x;
      mark_dead(x + 1, a[idx]);
      x = a[idx];
    };

    while (alive.query(0, n - 1) > 0) {
      int r = alive.min_left(idx, [&](int sum) { return sum > 0; });      // first alive to the right
      int l = alive.max_right(idx - 1, [&](int sum) { return sum > 0; }); // first alive to the left
      if (r == n) {
        sep = int(1e9) + 10;
        go_left();
        continue;
      }
      if (l == -1) {
        sep = int(1e9) + 10;
        go_right();
        continue;
      }
      int dl = x - a[l], dr = a[r] - x;
      if (dl <= dr) {
        sep = dr;
        go_left();
      } else {
        sep = dl;
        go_right();
      }
    }

    cout << ans << '\n';
  }
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...