RUPC 2016 Day3 F: Kitsuchiri

解法

答えるべき情報は対応する配列の値が全て同じか否かだけなので、保存する情報は S[i] と S[N-1-i] の差だけで良い。この差が全てのiについて0になれば左右対称であると言える。このことから、右半分は左半分との差分だけ保存して、左半分は全て0にして構わないことになる。

来るクエリについても、左半分に対するクエリとして全てを処理して構わない。

例えば、 N=10 の時、(l=3 r=6 x=10)というクエリが来た場合、i=5 と i=6 に同じクエリが来ても状態は変化しないので省略して (l=3 r=4 x=10) とクエリを読みかえることが出来る。さらに反転して左半分に対するクエリに変換してやると (l=7 r=8 x=-10)と考えることが出来る。

あとは StarrySky 木で区間に対するクエリを上手く処理して、全てが0になっていれば1を、そうでなければ0を返すようにすれば良い。

コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template <typename T>
std::ostream &operator<<(std::ostream &out, const std::vector<T> &v) {
  if (!v.empty()) {
    out << '[';
    std::copy(v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
    out << "\b\b]";
  }
  return out;
}
template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &out, const std::pair<T1, T2> &p) {
  out << "[" << p.first << ", " << p.second << "]";
  return out;
}
template <class T, class U>
void chmin(T &t, U f) {
  if (t > f) t = f;
}
template <class T, class U>
void chmax(T &t, U f) {
  if (t < f) t = f;
}

struct StarrySkyTree {
  static const int N = 1 << 20;

  vector<long long> seg_min, seg_max, seg_add;
  StarrySkyTree()
      : seg_min(N * 2, (long long)1e18),
        seg_max(N * 2, -1e18),
        seg_add(N * 2, 0) {}

  // Add x to [a, b)
  void add(int a, int b, int x, int k = 0, int l = 0, int r = N) {
    if (r <= a || b <= l) return;
    if (a <= l && r <= b) {
      seg_add[k] += x;
      while (k) {
        k = (k - 1) / 2;
        seg_min[k] = min(seg_min[k * 2 + 1] + seg_add[k * 2 + 1],
                         seg_min[k * 2 + 2] + seg_add[k * 2 + 2]);
        seg_max[k] = max(seg_max[k * 2 + 1] + seg_add[k * 2 + 1],
                         seg_max[k * 2 + 2] + seg_add[k * 2 + 2]);
      }
      return;
    }
    add(a, b, x, k * 2 + 1, l, (l + r) / 2);
    add(a, b, x, k * 2 + 2, (l + r) / 2, r);
  }

  void update(int k, long long value) {
    k += N - 1;
    seg_min[k] = value;
    seg_max[k] = value;
    while (k > 0) {
      k = (k - 1) / 2;
      seg_min[k] = min(seg_min[k * 2 + 1], seg_min[k * 2 + 2]);
      seg_max[k] = max(seg_max[k * 2 + 1], seg_max[k * 2 + 2]);
    }
  }

  //[a, b)
  long long get_min(int a, int b, int k = 0, int l = 0, int r = N) {
    if (r <= a || b <= l) return 1e18;
    if (a <= l && r <= b) return (seg_min[k] + seg_add[k]);
    long long x = get_min(a, b, k * 2 + 1, l, (l + r) / 2);
    long long y = get_min(a, b, k * 2 + 2, (l + r) / 2, r);
    return (min(x, y) + seg_add[k]);
  }

  //[a, b)
  long long get_max(int a, int b, int k = 0, int l = 0, int r = N) {
    if (r <= a || b <= l) return -1e18;
    if (a <= l && r <= b) return (seg_max[k] + seg_add[k]);
    long long x = get_max(a, b, k * 2 + 1, l, (l + r) / 2);
    long long y = get_max(a, b, k * 2 + 2, (l + r) / 2, r);
    return (max(x, y) + seg_add[k]);
  }
};

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N;
  cin >> N;
  vector<int> S(N);
  for (int i = 0; i < N; ++i) cin >> S[i];
  for (int i = 0; i < N / 2; ++i) {
    S[N - 1 - i] -= S[i];
    S[i] = 0;
  }
  StarrySkyTree sst;
  for (int i = 0; i < N; ++i) sst.update(i, S[i]);

  int Q;
  cin >> Q;
  while (Q--) {
    int l, r, x;
    cin >> l >> r >> x;
    if (l <= N / 2 && N / 2 <= r) {
      int lw = N / 2 - l + 1;
      int rw = r - N / 2;
      if (lw > rw) {
        r = N / 2 - rw;
      } else if (lw < rw) {
        l = N / 2 + 1 + lw;
      } else {
        goto print;
      }
    }
    l--, r--;
    if (r < N / 2) {
      l = N - 1 - l;
      r = N - 1 - r;
      swap(l, r);
      x = -x;
    }
    sst.add(l, r + 1, x);

  print:
    if (sst.get_max(0, N) == sst.get_min(0, N)) {
      cout << 1 << endl;
    } else {
      cout << 0 << endl;
    }
  }
}