luogu 4587

假设当前已经组合好了 $[1, x]$ ,设 $ans = x + 1$ ;显然初始时 $x = 0, ans = 1$
我们另 $y = \sum_{i = l} ^ {r} (w_i <= ans) * w_i$
如果 $ans <= y$,说明除了组合出 $[1, x]$ 中的数,
一定存在一个数满足 $<=x+1$
这个时候 $[1, y]$ 都可以组合出来,另 $ans = y + 1$ ;
如果 $ans>y$ ,说明除了组合出 $[1, x]$的数,
其余所有的数均 $> x + 1$ ,这样当前的 $ans$ 就是答案了
统计一个区间内 $<=k$ 的数的和可以用主席树来是实现

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int N = 1e5 + 10;

int W[N * 20], Root[N], Lson[N * 20], Rson[N * 20];
int n, A[N], B[N];

#define gc getchar()
inline int read() {
    int x = 0; char c = gc;
    while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    return x; 
}

int Seg_js;
void Fill(int x, int y) {W[x] = W[y]; Lson[x] = Lson[y]; Rson[x] = Rson[y];}

void Insert(int &jd, int l, int r, int x, int num) {
    Fill(++ Seg_js, jd);
    jd = Seg_js;
    W[jd] += num;
    if(l == r) return ; 
    int mid = (l + r) >> 1;
    if(x <= mid) Insert(Lson[jd], l, mid, x, num);
    else Insert(Rson[jd], mid + 1, r, x, num);
}

int Answer;

void Sec_A(int jd1, int jd2, int l, int r, int x) {
    if(l == r) {Answer += (W[jd2] - W[jd1]); return;}
    int mid = (l + r) >> 1;
    if(x <= mid) Sec_A(Lson[jd1], Lson[jd2], l, mid, x);
    else {
        Answer += (W[Lson[jd2]] - W[Lson[jd1]]);
        Sec_A(Rson[jd1], Rson[jd2], mid + 1, r, x);
    }
}

int Len;

inline int Find(int x) {
    int l = 1, r = Len, ret;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(B[mid] <= x) ret = mid, l = mid + 1;
        else r = mid - 1;
    }
    return ret;
}

int main() {
    n = read();
    for(int i = 1; i <= n; i ++) A[i] = read(), B[i] = A[i];
    sort(B + 1, B + n + 1);
    Len = unique(B + 1, B + n + 1) - B - 1;
    for(int i = 1; i <= n; i ++) {
        int t = lower_bound(B + 1, B + Len + 1, A[i]) - B;
        Root[i] = Root[i - 1];
        Insert(Root[i], 1, Len, t, A[i]);
    }
    int Q = read();
    for(; Q; Q --) {
        int l = read(), r = read();
        int Ans = 1;
        while(1) {
            int tmp = Find(Ans);
            Answer = 0;
            Sec_A(Root[l - 1], Root[r], 1, Len, tmp);
            if(Answer >= Ans) Ans = Answer + 1;
            else break;
        }
        printf("%d\n", Ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/shandongs1/p/9506557.html
今日推荐