Submission #1354543

#TimeUsernameProblemLanguageResultExecution timeMemory
1354543avighnaAnts and Sugar (JOI22_sugar)C++20
22 / 100
2669 ms1114112 KiB
#include <bits/stdc++.h>

using namespace std;

const int64_t inf = 1e15;

// let stt[N, C, D, CC, CD, DC, DD]
struct state {
private:
  inline static string lookup[7];
  static string idx_to_string(int idx) { return lookup[idx]; }
  static int idx_from_string(const string &s) {
    auto it = find(lookup, lookup + 7, s);
    assert(it != lookup + 7);
    return it - lookup;
  }

public:
  inline static int to[7][7];

  static void init() {
    lookup[0] = "N", lookup[1] = "C", lookup[2] = "D", lookup[3] = "CC", lookup[4] = "CD", lookup[5] = "DC", lookup[6] = "DD";
    for (int i = 0; i < 7; ++i) {
      for (int j = 0; j < 7; ++j) {
        if (i == 0) {
          to[i][j] = j;
        } else if (j == 0) {
          to[i][j] = i;
        } else {
          string comb = idx_to_string(i) + idx_to_string(j);
          if (idx_to_string(i).back() == idx_to_string(j).front()) {
            to[i][j] = -1;
          } else {
            to[i][j] = idx_from_string(string(1, comb.front()) + string(1, comb.back()));
          }
        }
      }
    }
  }

  int64_t stt[7];

  state() { // len>1 identity
    for (int i = 0; i < 7; ++i) { stt[i] = 0; }
  }
  static state get(int64_t len) {
    if (len != 1) {
      return state();
    }
    return state(0, 0);
  }
  state(int64_t c, int64_t d) {
    stt[0] = 0;     // N
    stt[1] = c;     // C
    stt[2] = d;     // D
    stt[3] = -inf;  // CC
    stt[4] = -inf;  // CD
    stt[5] = d + c; // DC
    stt[6] = -inf;  // DD
  }

  static state idt() {
    state res;
    for (int i = 0; i < 7; ++i) { res.stt[i] = -inf; }
    return res;
  }
  bool operator==(const state &r) const = default;
};

state operator+(const state &l, const state &r) {
  if (l == state::idt()) {
    return r;
  }
  if (r == state::idt()) {
    return l;
  }
  state res = state::idt();
  for (int i = 0; i < 7; ++i) {
    for (int j = 0; j < 7; ++j) {
      int which = state::to[i][j];
      if (which != -1) {
        res.stt[which] = max(res.stt[which], l.stt[i] + r.stt[j]);
      }
    }
  }
  return res;
}

template <typename T>
class sparse_segment_tree {
  struct node {
    T cur;
    int64_t lazy, lazy_c;
    node *l, *r;
    node(int64_t len) : l(nullptr), r(nullptr), lazy(0), lazy_c(0) {
      if constexpr (is_same_v<T, state>) {
        cur = T::get(len);
      } else {
        cur = T{};
      }
    }
    ~node() {
      delete l;
      delete r;
    }
  };

  int64_t tl, tr;
  node *t;

  void push(node *t, int64_t tl, int64_t tr) {
    // [N, C, D, CC, CD, DC, DD]
    if constexpr (is_same_v<T, state>) {
      static constexpr array<int, 7> m = {0, 1, -1, 1, 0, 0, -1};
      static constexpr std::array<int, 7> m_c = {0, 1, 0, 2, 1, 1, 1};
      for (int i = 0; i < 7; ++i) {
        t->cur.stt[i] += m[i] * t->lazy;
        t->cur.stt[i] += m_c[i] * t->lazy_c;
      }
      if (tl == tr) {
        t->lazy = 0, t->lazy_c = 0;
        return;
      }
      int64_t tm = midpoint(tl, tr);
      t->l = t->l ? t->l : new node(tm - tl + 1);
      t->r = t->r ? t->r : new node(tr - tm);
      t->l->lazy += t->lazy, t->l->lazy_c += t->lazy_c;
      t->r->lazy += t->lazy, t->r->lazy_c += t->lazy_c;
      t->lazy = 0, t->lazy_c = 0;
    }
  }

  void pull(node *t) {
    t->cur = t->l->cur + t->r->cur;
  }

  void set(node *t, int64_t tl, int64_t tr, int64_t i, T st) {
    push(t, tl, tr);
    if (tr < i || i < tl) {
      return;
    }
    if (tl == tr && tl == i) {
      t->cur = st;
      return;
    }
    int64_t tm = midpoint(tl, tr);
    t->l = t->l ? t->l : new node(tm - tl + 1);
    t->r = t->r ? t->r : new node(tr - tm);
    set(t->l, tl, tm, i, st);
    set(t->r, tm + 1, tr, i, st);
    pull(t);
  }

  T query(node *t, int64_t tl, int64_t tr, int64_t l, int64_t r) {
    push(t, tl, tr);
    if (tr < l || r < tl) {
      if constexpr (is_same_v<T, state>) {
        return T::idt();
      } else {
        return T{};
      }
    }
    if (l <= tl && tr <= r) {
      return t->cur;
    }
    int64_t tm = midpoint(tl, tr);
    t->l = t->l ? t->l : new node(tm - tl + 1);
    t->r = t->r ? t->r : new node(tr - tm);
    T res = query(t->l, tl, tm, l, r) + query(t->r, tm + 1, tr, l, r);
    pull(t);
    return res;
  }

  void add_same_suffix(node *t, int64_t tl, int64_t tr, int64_t l, int64_t x)
    requires is_same_v<T, state>
  {
    push(t, tl, tr);
    if (tr < l) {
      return;
    }
    if (l <= tl) {
      t->lazy += x;
      push(t, tl, tr);
      return;
    }
    int64_t tm = midpoint(tl, tr);
    t->l = t->l ? t->l : new node(tm - tl + 1);
    t->r = t->r ? t->r : new node(tr - tm);
    add_same_suffix(t->l, tl, tm, l, x);
    add_same_suffix(t->r, tm + 1, tr, l, x);
    pull(t);
  }

  void add_range_c(node *t, int64_t tl, int64_t tr, int64_t l, int64_t r, int64_t x)
    requires is_same_v<T, state>
  {
    push(t, tl, tr);
    if (tr < l || r < tl) {
      return;
    }
    if (l <= tl && tr <= r) {
      t->lazy_c += x;
      push(t, tl, tr);
      return;
    }
    int64_t tm = midpoint(tl, tr);
    t->l = t->l ? t->l : new node(tm - tl + 1);
    t->r = t->r ? t->r : new node(tr - tm);
    add_range_c(t->l, tl, tm, l, r, x);
    add_range_c(t->r, tm + 1, tr, l, r, x);
    pull(t);
  }

public:
  sparse_segment_tree(int64_t tl, int64_t tr) : tl(tl), tr(tr), t(new node(tr - tl + 1)) {}
  ~sparse_segment_tree() { delete t; }

  void set(int64_t i, T st) { set(t, tl, tr, i, st); }
  T query(int64_t l, int64_t r) { return query(t, tl, tr, l, r); }
  void add_same_suffix(int64_t l, int64_t x)
    requires is_same_v<T, state>
  {
    add_same_suffix(t, tl, tr, l, x);
  }
  void add_range_c(int64_t l, int64_t r, int64_t x)
    requires is_same_v<T, state>
  {
    add_range_c(t, tl, tr, l, r, x);
  }
};

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

  state::init();

  // coordinate space extends from -1e9 to 2e9

  // ants are    a[]
  // sugars are  b[]

  // operations: a[x] += val
  //             b[x] += val

  // what is the maximum matching from a -> b?
  // from a[i], there are edges to all of b[i-L], b[i-L+1], ..., b[i+L-1], b[i+L]
  // so let's just choose intervals [li, ri] of a[] values (subsets <=> intervals)
  // we must find the hall deficiency, that is:
  //
  // define cost(l,r) = sum(i=l to r) a[i] - sum(i=l-L to r+L) b[i]
  //
  // then max sum(cost(li, ri))

  // let's simplify. define A(x) = sum(i=1 to x) a[i], B(x) = sum(i=1 to x) b[i]
  // then cost(l,r) = (A(r) - A(l-1)) - (B(r+L) - B(l-L-1))
  //                = A(r)-B(r+L) - (A(l-1) - B(l-L-1))
  //
  // then, define c[x] = A(x)-B(x+L) and d[x] = B(x-L-1)-A(x-1), then

  // cost(l,r) = c[r] + d[l]. Think of c[] and d[] as arrays.

  // so as we span, we do
  // [p1,p2] [p3,p4] ==> d[p1] + c[p2] + d[p3] + c[p4],
  // which is DCDCDCDC

  int q, L;
  cin >> q >> L;

  int64_t lo = -1e9 - 10, hi = 2e9 + 10;
  sparse_segment_tree<int64_t> a(lo, hi), b(lo, hi);
  sparse_segment_tree<state> st(lo + L + 1, hi - L);

  // c[i] = A[i] - B[i+L]
  // d[i] = B[i-L-1] - A[i-1]

  // a[i] += x meaning =>
  // A[idx] += x for all idx >= i
  // meaning

  // c[idx] += x for all idx >= i
  // d[idx + 1] -= x for all idx >= i

  // b[i] += x meaning =>

  // c[idx] -= x for all idx >= i-L
  // d[idx] += x for all idx >= i+L+1

  auto compute = [&]() {
    return st.query(lo + L + 1, hi - L).stt[5];
  };

  int64_t sum_ants = 0;
  auto add_ants = [&](int x, int v) {
    sum_ants += v;
    a.set(x, a.query(x, x) + v);
    st.add_range_c(x, x, v);
    st.add_same_suffix(x + 1, v);
  };

  auto add_sugar = [&](int x, int v) {
    b.set(x, b.query(x, x) + v);
    st.add_same_suffix(x + L + 1, -v);
    st.add_range_c(x - L, x + L, -v);
  };

  while (q--) {
    int t, x, v;
    cin >> t >> x >> v;
    if (t == 1) {
      add_ants(x, v);
    } else {
      add_sugar(x, v);
    }
    cout << min(sum_ants, sum_ants - compute()) << '\n';
  }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...