TIOJ 1919:王老先生

TIOJ 1919王老先生


題目大意:有 $m$ 塊地,第 $i$ 塊屬於第 $a_i$ 個人,第 $i$ 個人想得到 $V_i$ 元,每次有一個區間
$[L_i, R_i]$,只要自己有地在這個區間裡,就可以拿 $C_i$ 元,問每個人在第幾個區間後就可以拿到自己想要的錢。 

解法:可以對區間們從 $1\sim Q+1$ 整體二分搜,每次二分搜時要處理 $l\sim mid$ 的區間,然後看第 $i$ 個人有沒有達成目標,若有,把他放到左邊那一組,若無,將 $V_i$ 扣掉 $l\sim mid$ 得到的錢,並放在右邊那一組。至於如何知道每個人得多少錢呢,可以將每個區間分成 $(L_i,L_i,C_i)$, $(R_i+1,L_i,-C_i)$,然後全部 $\text{push}$ 後排序,每次都用 $\text{BIT}$ 更新中間的 $L_i$ 的值,然後可以把需要用到的位置排序後來處理。可以用 $\text{last}$ 紀錄上一次出現的位置是哪裡。

$\text{Code:}$

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;

#define FOR(x,a,b) for(int x=a;x<=b;x++)
#define F first
#define S second
#define LL long long
#define pb emplace_back

const int SIZE = 1e5 + 5;

struct Ask {
    int l, r, c;
    Ask() {}
    Ask (int l, int r, int c) : l (l), r (r), c (c) {}
    bool operator < (const Ask &a) const {
        if (l!= a.l)
            return l < a.l;
        return r < a.r;
    }
} ask[SIZE];

int N, M, Q, qsiz;
int a[SIZE], V[SIZE], ans[SIZE];
int q[SIZE], q1[SIZE], q2[SIZE], last[SIZE];
LL bit[SIZE], sum[SIZE];
bool ok[SIZE];
vector<int> pos[SIZE];

void update (int p, int x) {
    for (; p <= M + 1; p += p & -p)
        bit[p] += x;
}

LL query (int p) {
    LL re = 0;
    for (; p; p -= p & -p)
        re += bit[p];
    return re;
}

void divide (int l, int r, int L, int R) {
    if (L > R)
        return;
    if (l == r) {
        FOR (i, L, R) ans[q[i]] = l;
        return;
    }
    int cnt1 = 0, cnt2 = 0, mid = (l + r) / 2, lp = 0;
    vector<Ask> p;
    vector<int> v;
    FOR (i, l, mid) {
        p.pb (ask[i].l, ask[i].l, ask[i].c);
        p.pb (ask[i].r + 1, ask[i].l, -ask[i].c);
    }
    FOR (i, L, R) {
        for (int x : pos[q[i]])
            v.pb (x);
    }
    sort (p.begin(), p.end());
    sort (v.begin(), v.end());
    for (int x : v) {
        while (lp < p.size() && p[lp].l <= x)
            update (p[lp].r, p[lp].c), lp++;
        sum[a[x]] += query (x) - query (last[a[x]]);
        last[a[x]] = x;
    }
    while (lp < p.size())
        update (p[lp].r, p[lp].c), lp++;
    FOR (i, L, R) {
        last[q[i]] = 0;
        if (sum[q[i]] >= V[q[i]])
            q1[++cnt1] = q[i];
        else {
            V[q[i]] -= sum[q[i]];
            q2[++cnt2] = q[i];
        }
        sum[q[i]] = 0;
    }
    FOR (i, 1, cnt1) q[L + i - 1] = q1[i];
    FOR (i, 1, cnt2) q[L + cnt1 + i - 1] = q2[i];
    divide (l, mid, L, L + cnt1 - 1);
    divide (mid + 1, r, L + cnt1, R);
}

void solve() {
    cin >> N >> M >> Q;
    FOR (i, 1, M) cin >> a[i], ok[a[i]] = 1, pos[a[i]].pb (i);
    FOR (i, 1, N) cin >> V[i];
    FOR (i, 1, Q) cin >> ask[i].l >> ask[i].r >> ask[i].c;
    FOR (i, 1, N) {
        if (V[i] == 0)
            ans[i] = 0;
        else if (!ok[i])
            ans[i] = -1;
        else
            q[++qsiz] = i;
    }
    divide (1, Q + 1, 1, qsiz);
    FOR (i, 1, N) cout << (ans[i] == Q + 1 ? -1 : ans[i]) << '\n';
}

int main() {
    ios::sync_with_stdio (false), cin.tie (0);
    solve();
}

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

留言

熱門文章