結果
問題 | No.1270 Range Arrange Query |
ユーザー | tsutaj |
提出日時 | 2020-09-19 00:46:28 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 3,952 ms / 7,000 ms |
コード長 | 11,257 bytes |
コンパイル時間 | 3,502 ms |
コンパイル使用メモリ | 169,832 KB |
実行使用メモリ | 5,376 KB |
最終ジャッジ日時 | 2024-06-28 05:21:27 |
合計ジャッジ時間 | 22,627 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 2 ms
5,376 KB |
testcase_02 | AC | 2 ms
5,376 KB |
testcase_03 | AC | 2 ms
5,376 KB |
testcase_04 | AC | 3 ms
5,376 KB |
testcase_05 | AC | 2 ms
5,376 KB |
testcase_06 | AC | 288 ms
5,376 KB |
testcase_07 | AC | 2,482 ms
5,376 KB |
testcase_08 | AC | 351 ms
5,376 KB |
testcase_09 | AC | 1,707 ms
5,376 KB |
testcase_10 | AC | 1,517 ms
5,376 KB |
testcase_11 | AC | 3,948 ms
5,376 KB |
testcase_12 | AC | 3,937 ms
5,376 KB |
testcase_13 | AC | 3,952 ms
5,376 KB |
testcase_14 | AC | 13 ms
5,376 KB |
testcase_15 | AC | 55 ms
5,376 KB |
testcase_16 | AC | 61 ms
5,376 KB |
testcase_17 | AC | 57 ms
5,376 KB |
ソースコード
#pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") // #define _GLIBCXX_DEBUG // for STL debug (optional) #include <iostream> #include <iomanip> #include <cstdio> #include <string> #include <cstring> #include <deque> #include <list> #include <queue> #include <stack> #include <vector> #include <utility> #include <algorithm> #include <map> #include <set> #include <complex> #include <cmath> #include <limits> #include <cfloat> #include <climits> #include <ctime> #include <cassert> #include <numeric> #include <fstream> #include <functional> #include <bitset> using namespace std; using ll = long long int; using int64 = long long int; template<typename T> void chmax(T &a, T b) {a = max(a, b);} template<typename T> void chmin(T &a, T b) {a = min(a, b);} template<typename T> void chadd(T &a, T b) {a = a + b;} int dx[] = {0, 0, 1, -1}; int dy[] = {1, -1, 0, 0}; const int INF = 1LL << 29; const ll LONGINF = 1LL << 60; const ll MOD = 1000000007LL; // Binary Indexed Tree (BIT) // Verified: AOJ DSL_2_B: Range Sum Query (intのみ) template <typename T> struct BIT{ private: vector<T> array; int n; public: // 初期化 BIT() {} BIT(int _n) : array(_n + 1, 0), n(_n) {} // 1番目から i番目までの累積和を求める T query(int i) { T s = 0; while(i > 0) { s += array[i]; i -= i & -i; // LSB 減算 } return s; } // [i, j) の要素の総和 T query(int i, int j) { j--; T ret_i = query(i-1); T ret_j = query(j); return ret_j - ret_i; } // i 番目に 要素 x を追加 void update(int i, T x) { while(i <= n) { array[i] += x; i += i & -i; // LSB 加算 } } }; // 次の2つのクエリに対応するBIT // ・[a, b) の要素全てに x を加えるクエリ // ・[a, b) の和を計算するクエリ // Verified: POJ 3468 (A Simple Problem with Integers) template <typename U> class BIT_sec { public: int n; BIT<U> bit0, bit1; BIT_sec(int n_) { n = n_; bit0 = BIT<U>(n); bit1 = BIT<U>(n); } // 最初に要素を追加するときはこっち void update(int i, int x) { bit0.update(i, x); } // [l, r) の全要素に x を加える void update(int l, int r, U x) { r--; bit0.update(l, -x * (l-1)); bit1.update(l, x); bit0.update(r+1, x*r); bit1.update(r+1, -x); } U query(int l, int r) { r--; U res = 0; res += bit0.query(r) + bit1.query(r) * r; res -= bit0.query(l-1) + bit1.query(l-1) * (l-1); return res; } }; // @category セグメント木 (Segment Tree) // @title 遅延伝播セグメント木 (Lazy Segment Tree) template <typename MonoidType, typename OperatorType> struct LazySegmentTree { using MMtoM = function< MonoidType(MonoidType, MonoidType) >; using OOtoO = function< OperatorType(OperatorType, OperatorType) >; using MOtoM = function< MonoidType(MonoidType, OperatorType) >; using OItoO = function< OperatorType(OperatorType, int) >; // node, lazy, update flag (for lazy), identity element int n; vector<MonoidType> node; vector<OperatorType> lazy; vector<bool> need_update; MonoidType E0; OperatorType E1; // update / combine / lazy / accumulate function MOtoM upd_f; MMtoM cmb_f; OOtoO lzy_f; OItoO acc_f; void build(int m, vector<MonoidType> v = vector<MonoidType>()) { if(v != vector<MonoidType>()) m = v.size(); n = 1; while(n < m) n *= 2; node = vector<MonoidType>(2*n-1, E0); lazy = vector<OperatorType>(2*n-1, E1); need_update = vector<bool>(2*n-1, false); if(v != vector<MonoidType>()) { for(int i=0; i<m; i++) { node[n-1+i] = v[i]; } for(int i=n-2; i>=0; i--) { node[i] = cmb_f(node[2*i+1], node[2*i+2]); } } } // initialize LazySegmentTree() {} LazySegmentTree(int n_, MonoidType E0_, OperatorType E1_, MOtoM upd_f_, MMtoM cmb_f_, OOtoO lzy_f_, OItoO acc_f_, vector<MonoidType> v = vector<MonoidType>()) : E0(E0_), E1(E1_), upd_f(upd_f_), cmb_f(cmb_f_), lzy_f(lzy_f_), acc_f(acc_f_) { build(n_, v); } void eval(int k, int l, int r) { if(!need_update[k]) return; node[k] = upd_f(node[k], acc_f(lazy[k], r - l)); if(r - l > 1) { lazy[2*k+1] = lzy_f(lazy[2*k+1], lazy[k]); lazy[2*k+2] = lzy_f(lazy[2*k+2], lazy[k]); need_update[2*k+1] = need_update[2*k+2] = true; } lazy[k] = E1; need_update[k] = false; } void update(int a, int b, OperatorType x, int l, int r, int k) { eval(k, l, r); if(b <= l or r <= a) return; if(a <= l and r <= b) { lazy[k] = lzy_f(lazy[k], x); need_update[k] = true; eval(k, l, r); } else { int mid = (l + r) / 2; update(a, b, x, l, mid, 2*k+1); update(a, b, x, mid, r, 2*k+2); node[k] = cmb_f(node[2*k+1], node[2*k+2]); } } MonoidType query(int a, int b, int l, int r, int k) { if(b <= l or r <= a) return E0; eval(k, l, r); if(a <= l and r <= b) return node[k]; int mid = (l + r) / 2; MonoidType vl = query(a, b, l, mid, 2*k+1); MonoidType vr = query(a, b, mid, r, 2*k+2); return cmb_f(vl, vr); } // update [a, b)-th element (applied value, x) void update(int a, int b, OperatorType x) { update(a, b, x, 0, n, 0); } // range query for [a, b) MonoidType query(int a, int b) { return query(a, b, 0, n, 0); } void dump() { fprintf(stderr, "[lazy]\n"); for(int i=0; i<2*n-1; i++) { if(i == n-1) fprintf(stderr, "xxx "); if(lazy[i] == E1) fprintf(stderr, " E "); else fprintf(stderr, "%3d ", lazy[i]); } fprintf(stderr, "\n"); fprintf(stderr, "[node]\n"); for(int i=0; i<2*n-1; i++) { if(i == n-1) fprintf(stderr, "xxx "); if(node[i] == E0) fprintf(stderr, " E "); else fprintf(stderr, "%3d ", node[i]); } fprintf(stderr, "\n"); } }; // Mo のアルゴリズム (以下の条件を満たすときにクエリを高速に処理可能) // ・オフラインクエリ // ・クエリの対象となる数列が不変 // ・区間の伸縮にかかる計算量が小さい struct Mo { int bucket, nl, nr, ptr; vector<int> left, right, query_idx; vector<bool> state; Mo(int N) : bucket(sqrt(N) + 1), nl(0), nr(N), ptr(0), state(N, true) { left = right = vector<int>(); } // 区間 [l, r) を追加 void insert(int l, int r) { left.push_back(l); right.push_back(r); } // ソートする (バケットごとに、バケット同じなら右端小さい順) void build() { query_idx = vector<int>(left.size()); iota(query_idx.begin(), query_idx.end(), 0); sort(query_idx.begin(), query_idx.end(), [&](int a, int b) { if(left[a] / bucket != left[b] / bucket) return left[a] < left[b]; return right[a] < right[b]; }); } // クエリを一つすすめて、そのクエリ id を返す int proceed() { if(ptr == query_idx.size()) return -1; int id = query_idx[ptr]; while(nl > left[id] ) operate(--nl, true); while(nr < right[id]) operate(nr++, false); while(nl < left[id] ) operate(nl++, true); while(nr > right[id]) operate(--nr, false); return query_idx[ptr++]; } void operate(int idx, bool left) { state[idx].flip(); if(state[idx]) add(idx, left); else del(idx, left); } void add(int idx, bool left); void del(int idx, bool left); }; // res := その区間由来の転倒数 int N, Q, ofs = 1; ll res = 0, pls = 0; vector<int> A; // SegmentTree<int> sl, sm, sr; BIT<int> sl, sm, sr; LazySegmentTree<int, int> sa; void Mo::add(int idx, bool left) { if(left) { sl.update(A[idx] + ofs, -1); sm.update(A[idx] + ofs, +1); sa.update(0, A[idx], -1); res += sl.query(A[idx] + 1 + ofs, N + ofs); res += sr.query(0 + ofs, A[idx] + ofs); } else { sr.update(A[idx] + ofs, -1); sm.update(A[idx] + ofs, +1); sa.update(A[idx] + 1, N, -1); res += sl.query(A[idx] + 1 + ofs, N + ofs); res += sr.query(0 + ofs, A[idx] + ofs); } pls = sa.query(0, N); } void Mo::del(int idx, bool left) { if(left) { sl.update(A[idx] + ofs, +1); sm.update(A[idx] + ofs, -1); sa.update(0, A[idx], +1); res -= sl.query(A[idx] + 1 + ofs, N + ofs); res -= sr.query(0 + ofs, A[idx] + ofs); } else { sr.update(A[idx] + ofs, +1); sm.update(A[idx] + ofs, -1); sa.update(A[idx] + 1, N, +1); res -= sl.query(A[idx] + 1 + ofs, N + ofs); res -= sr.query(0 + ofs, A[idx] + ofs); } pls = sa.query(0, N); } int main() { scanf("%d%d", &N, &Q); A.resize(N); for(int i=0; i<N; i++) scanf("%d", &A[i]), A[i]--; /* sl = SegmentTree<int>(N, 0, [](int a, int b) { return a + b; }, [](int a, int b) { return a + b; }); sm = sr = sl; */ sl = sm = sr = BIT<int>(N); // 区間 add, 区間 min sa = LazySegmentTree<int, int>(N, INF, 0, [](int a, int b) { return a + b; }, [](int a, int b) { return min(a, b); }, [](int a, int b) { return a + b; }, [](int a, int x) { return a; }, vector<int>(N, 0)); ll inv = 0; { /* SegmentTree<int> seg_inv(N, 0, [](int a, int b) { return a + b; }, [](int a, int b) { return a + b; }); */ BIT<int> seg_inv(N); vector<int> ord(N); iota(ord.begin(), ord.end(), 0); sort(ord.begin(), ord.end(), [&](int x, int y) { if(A[x] != A[y]) return A[x] > A[y]; return x > y; }); for(int i=0; i<N; i++) { inv += seg_inv.query(0 + ofs, ord[i] + ofs); seg_inv.update(ord[i] + ofs, +1); } } Mo mo(N); vector<int> len(Q); for(int i=0; i<Q; i++) { int l, r; scanf("%d%d", &l, &r); l--; mo.insert(l, r); len[i] = r - l; } mo.build(); res = inv; for(int i=0; i<N; i++) { sm.update(A[i] + ofs, +1); } vector<ll> ans(Q); for(int i=0; i<Q; i++) { int idx = mo.proceed(); ans[idx] = inv - res + 1LL * len[idx] * pls; } for(int i=0; i<Q; i++) { printf("%lld\n", ans[i]); } return 0; }