Codeforces Round #404 (Div.2) E. Anton and Permutation
解法
平方分割 + 2次元BITで解いた.[0...m] x [0...n] で二次元.m は n / sqrt(n).
l[i] から r[i] の間に完全に含まれているブロックは BIT 上で計算し,端っこの部分は生で持っている配列を使って計算する.
bit.sum(lb, a, rb, b) とすると lb から rb - 1 までのブロックにおける [a..b) の数を求められる.
計算量は O(Q * (sqrt(N) + log^2(N))).
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; template <typename T> class fenwick_tree2d { public: fenwick_tree2d(int h, int w) : H(h), W(w), dat(H, std::vector<T>(W)) {} void add(int i, int j, T value) { for(; i < H; i |= i + 1) { int jj = j; for(; jj < W; jj |= jj + 1) { dat[i][jj] += value; } } } // [0..i] x [0..j] T sum(int i, int j) const { T res = 0; for(; i >= 0; i = (i & (i + 1)) - 1) { int jj = j; for(; jj >= 0; jj = (jj & (jj + 1)) - 1) { res += dat[i][jj]; } } return res; } // [i1...i2) x [j1...j2) T sum(int i1, int j1, int i2, int j2) const { return sum(i2 - 1, j2 - 1) - sum(i1 - 1, j2 - 1) - sum(i2 - 1, j1 - 1) + sum(i1 - 1, j1 - 1); } private: int const H, W; std::vector<std::vector<T>> dat; }; int main() { int n, q; cin >> n >> q; vector<int> l(q), r(q); for(int i = 0; i < q; ++i) { cin >> l[i] >> r[i]; l[i]--; r[i]--; if(l[i] > r[i]) { swap(l[i], r[i]); } } vector<int> a(n); for(int i = 0; i < n; ++i) { a[i] = i; } int const B = sqrt(n) + 1; fenwick_tree2d<int> bit(n / B + 1, n); for(int i = 0; i < n; ++i) { bit.add(i / B, i, 1); } ll inv = 0; for(int i = 0; i < q; ++i) { if(l[i] != r[i]) { int lb = l[i] / B, rb = r[i] / B; if(lb + 1 < rb) { int l_lt = bit.sum(lb + 1, 0, rb, a[l[i]]); int l_gt = bit.sum(lb + 1, a[l[i]] + 1, rb, n); int r_lt = bit.sum(lb + 1, 0, rb, a[r[i]]); int r_gt = bit.sum(lb + 1, a[r[i]] + 1, rb, n); inv += l_gt - l_lt + r_lt - r_gt; } if(lb == rb) { for(int j = l[i] + 1; j < r[i]; ++j) { inv += (a[l[i]] < a[j] ? 1 : -1) + (a[r[i]] < a[j] ? -1 : 1); } } else { for(int j = l[i] + 1; j < (lb + 1) * B; ++j) { inv += (a[l[i]] < a[j] ? 1 : -1) + (a[r[i]] < a[j] ? -1 : 1); } for(int j = rb * B; j < r[i]; ++j) { inv += (a[l[i]] < a[j] ? 1 : -1) + (a[r[i]] < a[j] ? -1 : 1); } } inv += (a[l[i]] < a[r[i]] ? 1 : -1); bit.add(l[i] / B, a[l[i]], -1); bit.add(r[i] / B, a[r[i]], -1); swap(a[l[i]], a[r[i]]); bit.add(l[i] / B, a[l[i]], 1); bit.add(r[i] / B, a[r[i]], 1); } cout << inv << endl; } }
感想
メモリもTLEも怖すぎる.