题目链接
题目描述
众所周知,天才程序员菜哭武是一个伟大的厨师。这天,张老师和石头来到菜哭武家做客,想尝一尝菜哭武的手艺。
菜哭武手上有n种食材,每种食材个数无限多,编号为i的食材有一个美味度ai。一道菜中,每种编号的食材至多有一个,
而这道菜的美味度是这道菜包含的食材的美味度之和。
每次张老师会指定一个编号l, 石头会指定一个编号r(l <= r),然后菜哭武会在编号在[l, r]中的食材中选若干
种食材做菜。张老师和石头都是美食家,因此他们要求菜哭武依次做出美味度以1,2,3,4...这样依次加1递增的菜,
直到菜哭武用当前的食材无法做出美味度为x的菜。比如,某一个[l, r]中的食材的美味度依次为2, 1, 1, 1,7,那么
美味度为1, 2, 3, 4, 5的菜都是可以做出来的,而美味度为6的菜是无法做出来的,所以对于这对[l, r],x = 6。
张老师和石头一共会提出m个这样的[l, r]区间,对于每个区间,菜哭武想知道这个x是多少。
输入描述:
第一行一个整数n(1 <= n <= 105), 代表食材的个数。
第二行n个整数,用空格隔开,第i个整数ai代表编号为i的食材的美味度。(Σai <= 109)
第三行一个整数m(1 <= m <= 105),代表区间的个数。
接下来m行,每行一对整数l, r,代表一个区间。(1 <= l <= r <= n)
输出描述:
对于每一个区间,输出一行对应的答案。
很不错的一道题,一个问区间的连续上升的序列可以从1开始上升到哪一个值刚好就没有这个值。
我们可以随便列举一串数,可以发现会有这样的规律:
例一:1,1,4。我们发现,我们可以先找到1,然后再往上就是可以(1+1)得到2,但是我们可以发现构不成3,岂不是尴尬。所以是3.
例二:1,1,1,4。我们发现,这次我们就可以找到3了,(1+1+1)就可以直接得到3了,然后我们再去找4,发现可以找到4,然后向后推到的最大的就是(7),所以,我们找不到8,输出8。
例三:1,1,3,4。这次,我们通过(1+1)可以先找到2,然后再去找3,发现我们可以找到3,并且由3和比3小的数,我们组成的最大的数就是(5),然后既然能找到5,说明我们接下去只需要再找到6就可以继续往下推了,我们会不会找到6呢?(1+1+4)也就是6了,但是我们其实可以组成到(1+1+3+4 = 9),再往后,我们发现就组不成其他的东西了,所以答案就是10。
例四:2,3,5,7。我们发现这时候最好从0开始找,那么我们就是要先去找1,看看1存不存在,然而,我们发现1并不存在,那么就是意味着,输出为1。
……
从中我们就可以发现一些些的规律了,这个也正是我所需要的。
就像找零一样(这可不一定是个好比喻),我们总是要从最小的开始,然后向上叠加,那么我们就是要知道最小的数的和,然后我们才能再向上叠加,也就是我们现在在(1~X)是充满的话,我们现在要去找(X+1),我们可能会发现多个(X+1),那么便都加进来,我们假设这样的正整数N,我们如果找到有这样的(X+1),那么也就是意味着(1~X+1)是充满的,如果还有多个(X+1),那么我们不如可以看作是(X+1~2*(X+1)-1),因为我们本来就是有(X)的,我们既然能填充X,也就能填充这些,以此不断的类推即可。
那么就是不断的维护前缀和了,这才是最棘手的事情,如何去不断的维护前缀和呢?时间戳来维护差值吧,然后每个时间戳下面记录的对应的位置,对应的位置上的对应的数的权值累加,譬如说这里有个7,那么当我们再添加一个7的时候,就是在7这号位置上“+7”,变成了14。就是这样的一个思维,我们可以不断的去寻找最大上线的填充了。接下去所要做的就是一个维护一颗可持久化线段树,不同的时间戳的差值,也就是我们最后所要寻找的答案了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7, _UP = 1e9;
int N, M, root[maxN], tot, lc[40*maxN], rc[40*maxN], tree[40*maxN];
inline void insert(int &rt, int old, int l, int r, int pos)
{
rt = ++tot;
tree[rt] = tree[old] + pos;
lc[rt] = lc[old]; rc[rt] = rc[old];
if(l == r) return;
int mid = HalF;
if(pos <= mid) insert(lc[rt], lc[old], l, mid, pos);
else insert(rc[rt], rc[old], mid + 1, r, pos);
}
inline int Query(int x, int y, int l, int r, int pos)
{
if(l == r) return tree[x] - tree[y];
int mid = HalF;
if(pos <= mid) return Query(lc[x], lc[y], l, mid, pos);
else return tree[lc[x]] - tree[lc[y]] + Query(rc[x], rc[y], mid + 1, r, pos);
}
inline void init()
{
tot = 0;
memset(lc, 0, sizeof(lc));
memset(rc, 0, sizeof(rc));
memset(tree, 0, sizeof(tree));
}
int main()
{
scanf("%d", &N);
init();
for(int i=1, u; i<=N; i++)
{
scanf("%d", &u);
insert(root[i], root[i-1], 1, _UP, u);
}
scanf("%d", &M);
int sum = 0, l, r, tmp;
while(M--)
{
scanf("%d%d", &l, &r);
sum = 0;
while(sum < _UP)
{
tmp = Query(root[r], root[l-1], 1, _UP, sum + 1);
if(sum == tmp) break;
sum = tmp;
}
printf("%d\n", sum + 1);
}
return 0;
}