原题面
题目描述
定义一个可重复数字集合(S)的神秘数为最小的不能被(S)的子集的元素和表示的数
例如:(S = {1,1,1,4,13})
则:(1=1 \ 2 = 1 + 1 \ 3 = 1 + 1 + 1 \ 4 = 4 \ 5 = 1 + 4 \ 6 = 1 + 1 + 4 \ 7 = 1 + 1 + 1 + 4)
8不能被(S)的子集和表示,所以(S)的神秘数是8
现有一个长为(n)的序列,(m)次询问,每次询问输入(l,r),求(S={a_i | l le i le r })的神秘数
解析
先考虑一个询问怎么处理
将(l)到(r)的数排序后考虑依次加入每一个数
假设当前可以凑出([1, t))的数,那么计算(sum = sum_{a_i le t} {a_i})
如果(sum < t),显然(t)就是答案
如果(sum ge t),说明凑出([1, t))后一定剩下一个小于等于(t)的数,那么([1, sum])的数也可以凑出来,(t)移动到(sum + 1)
然后考虑多组询问,我们要快速查询([l, r])内小于等于(t)的(a_i)之和,就可以套主席树了
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 100005
#define MAXA 1000000000
typedef long long LL;
struct ChairmanTree {
struct Node {
Node *ls, *rs;
int sum;
} * root[MAXN];
void build();
void build(Node *, Node *, int, int, int);
int query(Node *, Node *, int, int, int, int);
} T;
int N, M, ans;
int a[MAXN];
char gc();
LL read();
void print(LL);
int main() {
N = read();
for (int i = 1; i <= N; ++i) a[i] = read();
T.build();
M = read();
while (M--) {
int l = read() - 1, r = read();
ans = 1;
while (1) {
int s = T.query(T.root[l], T.root[r], 1, MAXA, 1, ans);
if (s >= ans)
ans = s + 1;
else
break;
}
print(ans);
putchar('
');
}
return 0;
}
void ChairmanTree::build() {
for (int i = 1; i <= N; ++i) build(root[i - 1], root[i] = new Node(), 1, MAXA, a[i]);
}
void ChairmanTree::build(Node *pre, Node *cur, int L, int R, int v) {
if (L == R)
cur->sum = (pre ? pre->sum : 0) + v;
else {
int mid = (L + R) >> 1;
if (v <= mid) {
if (pre) cur->rs = pre->rs;
build(pre ? pre->ls : NULL, cur->ls = new Node(), L, mid, v);
} else {
if (pre) cur->ls = pre->ls;
build(pre ? pre->rs : NULL, cur->rs = new Node(), mid + 1, R, v);
}
cur->sum = 0;
if (cur->ls) cur->sum += cur->ls->sum;
if (cur->rs) cur->sum += cur->rs->sum;
}
}
int ChairmanTree::query(Node *pre, Node *cur, int L, int R, int l, int r) {
if (!cur) return 0;
if (L >= l && R <= r) return cur->sum - (pre ? pre->sum : 0);
int mid = (L + R) >> 1, res = 0;
if (l <= mid) res += query(pre ? pre->ls : NULL, cur->ls, L, mid, l, r);
if (r > mid) res += query(pre ? pre->rs : NULL, cur->rs, mid + 1, R, l, r);
return res;
}
inline char gc() {
static char buf[1000000], *p1, *p2;
if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
return p1 == p2 ? EOF : *p2++;
}
inline LL read() {
LL res = 0;
char ch = gc();
while (ch < '0' || ch > '9') ch = gc();
while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc();
return res;
}
inline void print(LL x) {
static int buf[30];
if (!x)
putchar('0');
else {
while (x) buf[++buf[0]] = x % 10, x /= 10;
while (buf[0]) putchar('0' + buf[buf[0]--]);
}
}
//Rhein_E