【線段樹求區間第一個不大於val的值】Lpl and Energy-saving Lamps
阿新 • • 發佈:2018-09-02
所有 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