571 字
3 分钟
BZOJ 4299 Codechef FRBSUM
Description
数集S的ForbiddenSum定义为无法用S的某个子集(可以为空)的和表示的最小的非负整数。 例如,S={1,1,3,7},则它的子集和中包含0(S’=∅),1(S’={1}),2(S’={1,1}),3(S’={3}),4(S’={1,3}),5(S’ = {1, 1, 3}),但是它无法得到6。因此S的ForbiddenSum为6。 给定一个序列A,你的任务是回答该数列的一些子区间所形成的数集的ForbiddenSum是多少。
Input
输入数据的第一行包含一个整数N,表示序列的长度。 接下来一行包含N个数,表示给定的序列A(从1标号)。 接下来一行包含一个整数M,表示询问的组数。 接下来M行,每行一对整数,表示一组询问。
Output
对于每组询问,输出一行表示对应的答案。
Sample Input
5
1 2 4 9 10
5
1 1
1 2
1 3
1 4
1 5
Sample Output
2
4
8
8
8
HINT
对于100%的数据,1≤N,M≤100000,1≤A_i≤10^9,1≤A_1+A_2+…+A_N≤10^9。
题解
可以看出
如果一个区间能组出1~n的数而且有一个数小于等于n+1
则这个区间一定能构造出 n+1
然后就可以了
用主席树维护一下就可以了
复习一下主席树
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 1e9;
struct Seg_Node
{
int l, r;
Seg_Node *ch[2];
int Sum;
} * root[100005], *null;
int a[100005];
Seg_Node *NewSeg_Node()
{
Seg_Node *S = new Seg_Node();
S->ch[0] = S->ch[1] = null;
return S;
}
void copy(Seg_Node *&a, Seg_Node *b)
{
if (b == null)
a = null;
else
a = NewSeg_Node(), *a = *b;
}
void Update(int v, int l, int r, Seg_Node *&rt1, Seg_Node *rt2)
{
copy(rt1, rt2);
if(rt1==null)
rt1=NewSeg_Node();
rt1->Sum += v;
rt1->l = l, rt1->r = r;
if (l == r)
return;
int m = l + r >> 1;
if (v <= m)
{
Update(v, l, m, rt1->ch[0], rt2->ch[0]);
}
else
{
Update(v, m + 1, r, rt1->ch[1], rt2->ch[1]);
}
}
int Query(int R, int l, int r, Seg_Node *rt1, Seg_Node *rt2)
{
if (R >= r)
return rt1->Sum - rt2->Sum;
int m = l + r >> 1;
if (R <= m)
return Query(R, l, m, rt1->ch[0], rt2->ch[0]);
return Query(R, l, m, rt1->ch[0], rt2->ch[0]) + Query(R, m + 1, r, rt1->ch[1], rt2->ch[1]);
}
int main()
{
null = new Seg_Node();
null->ch[0] = null->ch[1] = null;
root[0] = null;
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i++)
{
Update(a[i], 1, 1e9, root[i], root[i - 1]);
}
int m;
scanf("%d", &m);
int a, b, ans;
while (m--)
{
scanf("%d%d", &a, &b);
int res = 1;
ans = min(INF, Query(res, 1, 1e9, root[b], root[a - 1]));
while (ans >= res && res < 1e9)
{
res = ans + 1;
ans = min(INF, Query(res, 1, 1e9, root[b], root[a - 1]));
}
printf("%d\n", ans + 1);
}
}