結果
問題 | No.1270 Range Arrange Query |
ユーザー | tsutaj |
提出日時 | 2020-09-19 00:23:51 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 5,755 ms / 7,000 ms |
コード長 | 10,923 bytes |
コンパイル時間 | 2,166 ms |
コンパイル使用メモリ | 154,556 KB |
実行使用メモリ | 5,460 KB |
最終ジャッジ日時 | 2024-06-28 05:20:04 |
合計ジャッジ時間 | 29,796 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
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 | 2 ms
5,376 KB |
testcase_05 | AC | 2 ms
5,376 KB |
testcase_06 | AC | 412 ms
5,376 KB |
testcase_07 | AC | 3,613 ms
5,376 KB |
testcase_08 | AC | 506 ms
5,376 KB |
testcase_09 | AC | 2,472 ms
5,376 KB |
testcase_10 | AC | 2,238 ms
5,376 KB |
testcase_11 | AC | 5,725 ms
5,376 KB |
testcase_12 | AC | 5,725 ms
5,376 KB |
testcase_13 | AC | 5,755 ms
5,376 KB |
testcase_14 | AC | 17 ms
5,376 KB |
testcase_15 | AC | 86 ms
5,456 KB |
testcase_16 | AC | 91 ms
5,376 KB |
testcase_17 | AC | 80 ms
5,460 KB |
ソースコード
// #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; // @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"); } }; // @category セグメント木 (Segment Tree) // @title セグメント木 (Segment Tree) // 抽象 SegmentTree (0-indexed・一点更新・区間取得) template <typename MonoidType> struct SegmentTree { using Function = function< MonoidType(MonoidType, MonoidType) >; // node, identity element int n; vector<MonoidType> node; MonoidType E0; // update / combine function Function upd_f, cmb_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); 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 SegmentTree() {} SegmentTree(int n_, MonoidType E0_, Function upd_f_, Function cmb_f_, vector<MonoidType> v = vector<MonoidType>()) : E0(E0_), upd_f(upd_f_), cmb_f(cmb_f_) { build(n_, v); } // update k-th element (applied value: x) void update(int k, MonoidType x) { k += n - 1; node[k] = upd_f(node[k], x); while(k > 0) { k = (k - 1) / 2; node[k] = cmb_f(node[2*k+1], node[2*k+2]); } } // range query for [a, b) // 非再帰のアイデア: http://d.hatena.ne.jp/komiyam/20131202/1385992406 MonoidType query(int a, int b) { MonoidType vl = E0, vr = E0; for(int l=a+n, r=b+n; l<r; l>>=1, r>>=1) { if(l & 1) vl = cmb_f(vl, node[(l++)-1]); if(r & 1) vr = cmb_f(node[(--r)-1], vr); } return cmb_f(vl, vr); } }; // 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; ll res = 0, pls = 0; vector<int> A; SegmentTree<int> sl, sm, sr; LazySegmentTree<int, int> sa; void Mo::add(int idx, bool left) { if(left) { sl.update(A[idx], -1); sm.update(A[idx], +1); sa.update(0, A[idx], -1); res += sl.query(A[idx]+1, N); res += sr.query(0, A[idx]); } else { sr.update(A[idx], -1); sm.update(A[idx], +1); sa.update(A[idx]+1, N, -1); res += sl.query(A[idx]+1, N); res += sr.query(0, A[idx]); } pls = sa.query(0, N); } void Mo::del(int idx, bool left) { if(left) { sl.update(A[idx], +1); sm.update(A[idx], -1); sa.update(0, A[idx], +1); res -= sl.query(A[idx]+1, N); res -= sr.query(0, A[idx]); } else { sr.update(A[idx], +1); sm.update(A[idx], -1); sa.update(A[idx]+1, N, +1); res -= sl.query(A[idx]+1, N); res -= sr.query(0, A[idx]); } 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; // 区間 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; }); 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, ord[i]); seg_inv.update(ord[i], +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], +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; }