分类
标签
2-SAT AC自动机 BFS CDQ dfs DP fail树 FFT FFT&NTT FWT hash KD-Tree KMP LCA SPFA STL Tarjan Treap Trie 主席树 乱搞 二分 二分图匹配 二分答案 二维SPFA 交互 位运算 其他 最小生成树 分块 区间DP 半平面交 博弈论 可持久化 可持久化Trie树 后缀数组 图库 平衡树 并查集 插头DP 数学 数论 无旋Treap 日记 暴力 权值树状数组 栈 树DP 树套树 树状数组 树贪心 概率DP 模拟 欧拉定理 点分治 状压DP 生成函数 矩阵乘 线性规划 线段树 组合 网络流 群论 莫比乌斯反演 计算几何 贪心 费用流 高斯消元
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);
}
}