TIOJ 2202:King Game

TIOJ 2202:King Game


題目大意:給你兩個大小為 $n$ 的陣列 $a_1\sim a_n,w_1\sim w_n$,有 $q$ 筆獨立的詢問,每次給你 $l, r, x, y$,將 $a_i$ 改變的花費為 $w_i$,問你最少要花費多少讓 $a_l\sim a_r$ 相異數字數界在 $[x,y]$。

解法:可以分成三種 $\text{case}$,令 $\text{tot}$ 為 $[l, r]$ 相異數字數,第一種是 $x\leq\text{tot}\leq y$,那答案就是 $0$,第二種是 $\text{tot} < x$,那要增加 $x-\text{tot}$ 個新的數字,做法就是把所有種類數值中 $w$ 最大的去掉,剩下的選前 $x-\text{tot}$ 小的,第三種是 $y>\text{tot}$,那有 $y-\text{tot}$ 種數值要去掉,可以把所有數值的 $w$ 加總,然後取前 $y-\text{tot}$ 小的。

我第一個做法是莫隊 $\text{+ multiset}$ 和用 $\text{Treap}$ 維護前 $k$ 小的總和,然後就 $\text{TLE + WA}$ 了,我的第二個做法是改成用 $\text{Trie}$ 維護前 $k$ 小,$\text{multiset}$ 改用回滾莫隊,結果還是 $\text{TLE}$ 😭。

最終的做法是用分塊去記錄,這樣可以把 $\text{log}$ 壓掉,$\text{debug}$ 了一整天$\dots$。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout << "[" << #HEHE << "] : ", dout(HEHE)
void dout() {cout << '\n';}
template<typename T, typename...U>
void dout(T t, U...u) {cout << t << (sizeof...(u) ? ", " : ""), dout(u...);}
#else
#define debug(...) 7122
#endif

#define ll long long
#define Waimai ios::sync_with_stdio(false), cin.tie(0)
#define FOR(x,a,b) for (int x = a, I = b; x <= I; x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 1e5 + 5;

int n, q, sq;
ll ans[SIZE], sum[SIZE];
int a[SIZE], w[SIZE], B[SIZE];
vector<tuple<int, int, int>> op;
int q1, q2, tot, cnt[SIZE], mx[SIZE];

struct Ask {
    int l, r, x, y, id;
    bool operator < (const Ask& rhs) const {
        return B[l] != B[rhs.l] ? l < rhs.l : r < rhs.r;
    }
} ask[SIZE], ask1[SIZE], ask2[SIZE];

struct SqrtDs {
    int c0[SIZE], c1[SIZE];
    ll sum[SIZE];
    void clear() {
        memset(c0, 0, sizeof(c0));
        memset(c1, 0, sizeof(c1));
        memset(sum, 0, sizeof(sum));
    }
    void add(int val, int coef) {
        if (val == 0) return;
        c0[val] += coef;
        c1[val / sq] += coef;
        sum[val / sq] += coef > 0 ? val : -val;
    }
    ll que(int k) {
        int p = 0;
        ll re = 0;
        for (; k && c1[p] <= k; p++) if (c1[p]) {
            k -= c1[p];
            re += sum[p];
        }
        for (p = sq * p; k; p++) if (c0[p]) {
            int num = min(k, c0[p]);
            k -= num;
            re += 1ll * num * p;
        }
        return re;
    }
} ds;

struct SqrtDs2 {
    const static int BSIZ = 2500;
    unordered_map<ll, int> mp;
    int c1[BSIZ * BSIZ + 5], c2[BSIZ + 5];
    ll sum1[BSIZ * BSIZ + 5], sum2[BSIZ + 5];
    void add(ll val, int coef) {
        if (val == 0) return;
        mp[val] += coef;
        if (mp[val] == 0) mp.erase(val);
        c1[val / BSIZ] += coef;
        c2[val / BSIZ / BSIZ] += coef;
        sum1[val / BSIZ] += coef > 0 ? val : -val;
        sum2[val / BSIZ / BSIZ] += coef > 0 ? val : -val;
    }
    ll que(int k) {
        ll p = 0, re = 0;
        for (; k && c2[p] <= k; p++) if (c2[p]) {
            k -= c2[p];
            re += sum2[p];
        }
        for (p = BSIZ * p; k && c1[p] <= k; p++) if (c1[p]) {
            k -= c1[p];
            re += sum1[p];
        }
        for (p = BSIZ * p; k; p++) if (mp.count(p)) {
            int num = min(k, mp[p]);
            k -= num;
            re += num * p;
        }
        return re;
    }
} ds2;

void solve() {
    cin >> n >> q;
    FOR (i, 1, n) cin >> a[i];
    FOR (i, 1, n) cin >> w[i];
    sq = sqrt(n);
    FOR (i, 1, n) B[i] = (i - 1) / sq;
    FOR (i, 1, q) {
        auto &[l, r, x, y, id] = ask[i];
        cin >> l >> r >> x >> y;
        id = i;
    }
    sort(ask + 1, ask + q + 1, [](auto lhs, auto rhs) {
        return B[lhs.l] != B[rhs.l] ? lhs.l < rhs.l : (B[lhs.l] & 1) ? lhs.r > rhs.r : lhs.r < rhs.r;
    });
    for (int i = 1, l = 1, r = 0; i <= q; i++) {
        auto [ql, qr, x, y, id] = ask[i];
        auto add = [](int i) {
            tot += cnt[a[i]]++ == 0;
        };
        auto del = [](int i) {
            tot -= --cnt[a[i]] == 0;
        };
        while (l > ql) add(--l);
        while (r < qr) add(++r);
        while (l < ql) del(l++);
        while (r > qr) del(r--);
        if (tot < x) ask1[++q1] = {ql, qr, x - tot, 0, id};
        if (tot > y) ask2[++q2] = {ql, qr, tot - y, 0, id};
    }
    sort(ask1 + 1, ask1 + q1 + 1);
    FOR (i, 1, q1) {
        auto [l, r, x, y, id] = ask1[i];
        if (B[l] == B[r]) {
            vector<int> v;
            FOR (j, l, r) {
                if (w[j] > mx[a[j]]) {
                    if (mx[a[j]]) v.pb(mx[a[j]]);
                    mx[a[j]] = w[j];
                } else {
                    v.pb(w[j]);
                }
            }
            FOR (j, l, r) mx[a[j]] = 0;
            x--;
            nth_element(v.begin(), v.begin() + x, v.end());
            FOR (j, 0, x) ans[id] += v[j];
            continue;
        }
        int ri = i + 1, mxl = 0;
        while (ri <= q1 && B[l] == B[ask1[ri].l]) ri++;
        ri--;
        FOR (j, i, ri) mxl = max(mxl, ask1[j].l);
        auto addl = [](int i) {
            if (w[i] > mx[a[i]]) {
                op.pb(a[i], mx[a[i]], mx[a[i]]);
                ds.add(mx[a[i]], 1);
                mx[a[i]] = w[i];
            } else {
                op.pb(a[i], w[i], mx[a[i]]);
                ds.add(w[i], 1);
            }
        };
        auto addr = [](int i) {
            if (w[i] > mx[a[i]]) {
                ds.add(mx[a[i]], 1);
                mx[a[i]] = w[i];
            } else {
                ds.add(w[i], 1);
            }
        };
        auto rollback = []() {
            reverse(op.begin(), op.end());
            for (auto [x, val, ori] : op) {
                ds.add(val, -1);
                mx[x] = ori;
            }
            op.clear();
        };
        int rp = mxl - 1;
        FOR (j, i, ri) {
            auto [l, r, x, y, id] = ask1[j];
            while (rp < r) addr(++rp);
            FOR (k, l, mxl - 1) addl(k);
            ans[id] = ds.que(x);
            rollback();
        }
        FOR (j, mxl, rp) mx[a[j]] = 0;
        ds.clear();
        i = ri;
    }
    for (int i = 1, l = 1, r = 0; i <= q2; i++) {
        auto [ql, qr, x, y, id] = ask2[i];
        auto add = [](int i) {
            ds2.add(sum[a[i]], -1);
            sum[a[i]] += w[i];
            ds2.add(sum[a[i]], 1);
        };
        auto del = [](int i) {
            ds2.add(sum[a[i]], -1);
            sum[a[i]] -= w[i];
            ds2.add(sum[a[i]], 1);
        };
        while (l > ql) add(--l);
        while (r < qr) add(++r);
        while (l < ql) del(l++);
        while (r > qr) del(r--);
        ans[id] = ds2.que(x);
    }
    FOR (i, 1, q) cout << ans[i] << '\n';
}

int main() {
    Waimai;
    solve();
}

我的分享就到這裡結束了,如果喜歡我的 $\text{Blog}$,歡迎追蹤! 

留言

熱門文章