結果

問題 No.5012 Better Mo's Algorithm is Needed!! (Execute)
ユーザー conlacdaconlacda
提出日時 2024-07-11 23:40:23
言語 C++23(gcc13)
(gcc 13.2.0 + boost 1.83.0)
結果
WA  
実行時間 -
コード長 6,897 bytes
コンパイル時間 4,917 ms
コンパイル使用メモリ 308,548 KB
実行使用メモリ 14,268 KB
スコア 0
最終ジャッジ日時 2024-07-11 23:41:42
合計ジャッジ時間 78,061 ms
ジャッジサーバーID
(参考情報)
judge3 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 WA -
testcase_01 WA -
testcase_02 WA -
testcase_03 WA -
testcase_04 WA -
testcase_05 WA -
testcase_06 WA -
testcase_07 TLE -
testcase_08 TLE -
testcase_09 TLE -
testcase_10 TLE -
testcase_11 TLE -
testcase_12 TLE -
testcase_13 TLE -
testcase_14 TLE -
testcase_15 TLE -
testcase_16 TLE -
testcase_17 TLE -
testcase_18 TLE -
testcase_19 TLE -
testcase_20 TLE -
testcase_21 TLE -
testcase_22 WA -
testcase_23 WA -
testcase_24 WA -
testcase_25 WA -
testcase_26 WA -
testcase_27 WA -
testcase_28 WA -
testcase_29 WA -
testcase_30 WA -
testcase_31 WA -
testcase_32 WA -
testcase_33 WA -
testcase_34 WA -
testcase_35 WA -
testcase_36 WA -
testcase_37 WA -
testcase_38 WA -
testcase_39 WA -
testcase_40 WA -
testcase_41 WA -
testcase_42 WA -
testcase_43 WA -
testcase_44 WA -
testcase_45 WA -
testcase_46 WA -
testcase_47 WA -
testcase_48 WA -
testcase_49 WA -
testcase_50 WA -
testcase_51 WA -
testcase_52 WA -
testcase_53 WA -
testcase_54 WA -
testcase_55 WA -
testcase_56 WA -
testcase_57 WA -
testcase_58 WA -
testcase_59 WA -
testcase_60 WA -
testcase_61 WA -
testcase_62 WA -
testcase_63 WA -
testcase_64 TLE -
testcase_65 TLE -
testcase_66 TLE -
testcase_67 TLE -
testcase_68 TLE -
testcase_69 TLE -
testcase_70 TLE -
testcase_71 TLE -
testcase_72 TLE -
testcase_73 TLE -
testcase_74 TLE -
testcase_75 TLE -
testcase_76 TLE -
testcase_77 TLE -
testcase_78 TLE -
testcase_79 TLE -
testcase_80 TLE -
testcase_81 TLE -
testcase_82 TLE -
testcase_83 TLE -
testcase_84 TLE -
testcase_85 TLE -
testcase_86 TLE -
testcase_87 TLE -
testcase_88 TLE -
testcase_89 TLE -
testcase_90 TLE -
testcase_91 TLE -
testcase_92 TLE -
testcase_93 TLE -
testcase_94 TLE -
testcase_95 TLE -
testcase_96 TLE -
testcase_97 TLE -
testcase_98 TLE -
testcase_99 TLE -
権限があれば一括ダウンロードができます

ソースコード

diff #

// https://judge.yosupo.jp/problem/static_range_inversions_query
#pragma GCC optimize("O3") // optimize("Ofast,unroll-loops")
#include<bits/stdc++.h>

typedef long long ll; // double long double
const ll mod = 1000000007; // 998244353  1000000009  1000000007 // đừng dùng ull
#define int long long // __int128
const int INF = std::numeric_limits<int>::max(); // INT32_MAX  DBL_MAX

using namespace std;

#ifdef DEBUG
#include "debug.cpp"
#else
#define dbg(...)
#endif

template<typename T = int>
struct Compress {
    vector<T> rcv; // recover - giá trị mảng ban đầu đã sort và xóa unique
    vector<T> cpr; // compressed - giá trị đã nén của mảng a
    Compress() {}
    Compress(vector<T>& a) { build(a);}
    void build(vector<T>& a) {
        rcv = a;
        sort(rcv.begin(), rcv.end());
        rcv.resize(unique(rcv.begin(), rcv.end()) - rcv.begin());

        cpr.resize(a.size());
        for (int i = 0; i < (int) cpr.size(); ++i) 
            cpr[i] = lower_bound(rcv.begin(), rcv.end(), a[i]) - rcv.begin(); // O(logN) thay cho map
    }
    T compressed_val(T originalVal) { // giá trị ban đầu sang giá trị đã compress
        T i = lower_bound(rcv.begin(), rcv.end(), originalVal) - rcv.begin();
        if (rcv[i] != originalVal) return -1;
        return i;
    }
    T operator[] (int index) {
        return cpr[index];
    }
    T original_val(T compressedVal) {
        return rcv[compressedVal];
    }   
};

// Range query, point update
template <typename T = int>
struct FenwickTree {
private:
    vector<T> bit; // binary indexed tree
    T n;
public:
    FenwickTree(){}
    void build(T n) { this->n = n; bit.assign(n, 0); }
    void build(vector<T> a) { build(a.size()); for (int i = 0; i < (int) a.size(); i++) add(i, a[i]); }
    FenwickTree(vector<T> a) { build(a); }
    T sum(T r) {
        if (r==-1) return 0;
        T ret = 0;
        for (; r >= 0; r = (r & (r + 1)) - 1) ret += bit[r];
        return ret;
    }

    T sum(T l, T r) {
        if (!(0 <= l && l <= r && r < n)) return 0;
        // assert(0 <= l && l <= r && r < n);
        return sum(r) - sum(l-1);
    }

    void add(T idx, T delta) {
        assert(0 <= idx && idx < n);
        for (; idx < n; idx = idx | (idx + 1)) bit[idx] += delta;
    }
    void set(T idx, T val) {
        T diff = val - sum(idx, idx);
        add(idx, diff);
    }

    vector<T> original(){ // Return original value of input vector
        vector<T> a;
        for (T i=0;i<this->n;i++) a.push_back(sum(i,i));
        return a;
    }

    int sum_from(int idx) {
        return sum(idx, n-1);
    }
    
    // Tìm ra index x nhỏ nhất để sum(start_index, x) >= K
    // nếu không có x nào thỏa mãn -> return n-1
    int firstIndexWithSumFromK(int start_index, int K) {
        int l = start_index, r = n-1;
        while (l < r) {
            int mid = (l + r) / 2;
            if (sum(start_index, mid) >= K) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

inline int64_t hilbertOrder(int x, int y, int pow = 21, int rotate = 0) { // 2**pow là số lượng query sẽ xử lý
    if (pow == 0) return 0;
    int hpow = 1 << (pow-1);
    int seg = (x < hpow) ? ((y < hpow) ? 0 : 3) : ((y < hpow) ? 1 : 2);
    seg = (seg + rotate) & 3;
    const int rotateDelta[4] = {3, 0, 0, 1};
    int nx = x & (x ^ hpow), ny = y & (y ^ hpow);
    int nrot = (rotate + rotateDelta[seg]) & 3;
    int64_t subSquareSize = int64_t(1) << (2*pow - 2);
    int64_t ans = seg * subSquareSize;
    int64_t add = hilbertOrder(nx, ny, pow-1, nrot);
    ans += (seg == 1 || seg == 2) ? add : (subSquareSize - add - 1);
    return ans;
}

struct Query {
    int l, r, index;
    ll ord = -1;
    friend bool operator<(Query& a, Query& b) {
        return a.ord < b.ord;
    }
};

struct Mo {
private:
    vector<int> a; // mảng đầu vào
public:
    FenwickTree<int> fw;
    vector<int> ans;
    int cur_result = 0; // giá trị hiện tại, đối với những bài giá trị tuyến tính khi add, remove thì dùng, ko thì tính trực tiếp từ mảng data
    Mo(vector<int>& a) {
        this->a = a;
        fw = FenwickTree(vector<int>(a.size(), 0));
    }
    void addLeft(int index) {
        cur_result += fw.sum(0, a[index] - 1);
        fw.add(a[index], 1);
    }
    void addRight(int index) {
        cur_result += fw.sum_from(a[index] + 1);
        fw.add(a[index], 1);
    }
    void removeLeft(int index) {
        cur_result -= fw.sum(0, a[index] - 1);
        fw.add(a[index], -1);
    }
    void removeRight(int index) {
        cur_result -= fw.sum_from(a[index] + 1);
        fw.add(a[index], -1);
    }
    ll getResult() {
        return this->cur_result;
    }
    vector<int> solve(vector<Query>& queries) {
        for (auto& q: queries) q.ord = hilbertOrder(q.l, q.r);
        sort(queries.begin(), queries.end());
        ans.resize(queries.size());
        ll left = 0, right = -1;
        for (auto query: queries) {
            while (left > query.l) left--, addLeft(left);
            while (right < query.r) right++, addRight(right);
            while (left < query.l) removeLeft(left), left++;
            while (right > query.r) removeRight(right), right--;
            ans[query.index] = getResult();
        }
        return ans;
    }
};

signed main(){
    ios::sync_with_stdio(0); cin.tie(0);
    cout << std::fixed << setprecision(15);
#ifdef DEBUG
    freopen("inp.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int n, q;
    cin >> n >> q;
    vector<int> a(n);
    for (auto&v: a) cin >> v;
    Compress com(a);
    a = com.cpr;
    Mo mo(a);
    vector<Query> queries;
    for (int i=0;i<q;i++) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        queries.push_back({u, v, i});
    }
    mo.solve(queries);
    for (auto v: mo.ans) cout << v << '\n';
    // dbg(mo.ans);

    cerr << "Time : " << (double)clock() / (double)CLOCKS_PER_SEC << "s✅\n";
}
/*
Bài này dùng Mo
Khi này data (cửa số dữ liệu) sẽ duy trì 1 set.
Bài toán khi này trở thành thêm 1 phần tử vào trái thì có bao nhiêu phần tử phải nhỏ hơn nó
và thêm vào phải thì trái bao nhiêu phần tử lớn hơn nó
Thoạt nhìn thì có thể sử dụng set để thêm 1 phần tử rồi theo order 
rồi dùng binary search tìm ra được có bao nhiêu số lớn/nhỏ hơn nó
=> thực ra thì ko có cách nào cả với set kể cả policy based set

Tại đây sử dụng fenwicktree.
* Compress mảng thành dạng index
* Dựng fenwicktree với mảng full 0
* thêm phần tử thì tăng index đó lên 1
* đếm số lượng phần tử nhỏ hơn hay lớn hơn thì đơn giản là lấy sum vì khi này a[index] chính là index trên fw
=> cửa sổ dữ liệu được maintain bằng cách sử dụng fw
*/
0