1. 程式人生 > >【線段樹求區間第一個不大於val的值】Lpl and Energy-saving Lamps

【線段樹求區間第一個不大於val的值】Lpl and Energy-saving Lamps

所有 href const clas main include uri i++ ant

https://nanti.jisuanke.com/t/30996

線段樹維護區間最小值,查詢的時候優先向左走,如果左邊已經找到了,就不用再往右了。
一個房間裝滿則把權值標記為INF,模擬一遍,註意考慮一個月內裝滿多個房間裝滿所有房間後不用再購買的情況。

代碼:

#include <iostream>
#include <cstdio>
#include <algorithm>
const int maxn = 100005;
const int INF = 0x3f3f3f3f;
using namespace std;
int a[maxn], St[maxn << 2], Q[maxn], ans[maxn], remain[maxn];
void PushUp(int rt) {
    St[rt] = min(St[rt << 1], St[rt << 1 | 1]);
}
void Build(int l, int r, int rt) {
    if (l == r) {
        St[rt] = a[l];
        return;
    }
    int m = (l + r) >> 1;
    Build(l, m, rt << 1);
    Build(m + 1, r, rt << 1 | 1);
    PushUp(rt);
}
void Update(int L, int C, int l, int r, int rt) {
    if (l == r) {
        St[rt] = C;
        return;
    }
    int m = (l + r) >> 1;
    if (L <= m) {
        Update(L, C, l, m, rt << 1);
    }
    else {
        Update(L, C, m + 1, r, rt << 1 | 1);
    }
    PushUp(rt);
}
int Query(int val, int L, int R, int l, int r, int rt) {
    if (l == r) {
        if (St[rt] <= val) {
            return l;
        }
        return INF;
    }
    if (L <= l && R >= r) {
        if (St[rt] > val) {
            return INF;
        }
    }
    int m = (l + r) >> 1;
    int ANS = INF;
    if (L <= m) ANS = min(ANS, Query(val, L, R, l, m, rt << 1));
    if (ANS != INF) {
        return ANS;
    }
    if (R > m) ANS = min(ANS, Query(val, L, R, m + 1, r, rt << 1 | 1));
    return ANS;
}
int main() {
    int n, m, q, mxq = 0;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    scanf("%d", &q);
    for (int i = 1; i <= q; i++) {
        scanf("%d", &Q[i]);
        mxq = max(mxq, Q[i]);
    }
    Build(1, n, 1);
    for (int i = 1, now = m, fin = 0; i <= mxq; i++, fin >= n ? 0 : now += m) {
        int p = Query(now, 1, n, 1, n, 1);
        ans[i] = ans[i - 1];
        while (p != INF) {
            fin++;
            ans[i]++;
            now -= a[p];
            Update(p, INF, 1, n, 1);
            p = Query(now, 1, n, 1, n, 1);
        }
        remain[i] = now;
    }
    for (int i = 1; i <= q; i++) {
        printf("%d %d\n", ans[Q[i]], remain[Q[i]]);
    }
}

【線段樹求區間第一個不大於val的值】Lpl and Energy-saving Lamps