题意:给出1e5个数 查询l,r区间内第一个不能被表示的数
比如1,2,4可以用子集的和表示出[1,7] 所以第一个不能被表示的是8
题解:先考虑暴力的做法 把这个区间内的数字按从小到大排序后
从前往后扫 当前能表示出[1,x] 假设第i个数字y-1<=x 那么就可以表示[1,x+y]
如果y > x + 1那么第一个不能表示出的数字就是x+1
我们根据这个性质来想 假如当前区间能表示出[1,x] 我们计算这个区间内所有比x小的数的和tmp
如果tmp>x 那么我们显然可以表示出[1,tmp] 反之x+1就是答案 直接退出就好
然后就用主席树来做求和这个东西
#include <bits/stdc++.h> using namespace std; const int INF = 1e9 + 5; const int MAXN = 1e5 + 5; int n, cnt; int sum[MAXN << 5]; int ls[MAXN << 5], rs[MAXN << 5]; int t[MAXN]; int inser(int o, int l, int r, int pos, int val) { int rt = ++cnt; ls[rt] = ls[o], rs[rt] = rs[o], sum[rt] = sum[o] + val; int m = l + r >> 1; if(l < r) if(pos <= m) ls[rt] = inser(ls[o], l, m, pos, val); else rs[rt] = inser(rs[o], m + 1, r, pos, val); return rt; } int query(int x, int y, int l, int r, int ql, int qr) { if(ql <= l && qr >= r) return sum[y] - sum[x]; int m = l + r >> 1; int res = 0; if(ql <= m) res += query(ls[x], ls[y], l, m, ql, qr); if(qr > m) res += query(rs[x], rs[y], m + 1, r, ql, qr); return res; } int main() { cnt = 0; scanf("%d", &n); for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); t[i] = inser(t[i - 1], 1, INF, x, x); } int T; scanf("%d", &T); while(T--) { int l, r; scanf("%d%d", &l, &r); int ans = 1; while(1) { int tmp = query(t[l - 1], t[r], 1, INF, 1, ans); if(tmp >= ans) ans = tmp + 1; else break; } printf("%d ", ans); } return 0; }