一个显然的性质:如果之前可以组成前mx个数,那么可以新加入一个<=mx+1的数构成一个更大的mx,如果>max+1则对当前无贡献
但是。。。推出这个性质后面我就没想到了。。。。
其实,每当我们得到一个mx以后,因为小于等于mx+1的数都可以和mx构成一个新的mx,因此新的mx=sum[mx+1],sum表示小于等于mx+1的前缀和,而这样每一次都至少增加一倍所以最多log次,主席树维护前缀和就好了
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 100021
#define LL long long
using namespace std;
int n,m,ls[maxn*40],rs[maxn*40],tot,rt[maxn];
LL sum[maxn*40];
void insert(int x,int& y,int l,int r,int id){
y=++tot;ls[y]=ls[x],rs[y]=rs[x];sum[y]=sum[x]+id;
if(l==r)return;
int mid=l+r>>1;
if(id>mid)insert(rs[x],rs[y],mid+1,r,id);
else insert(ls[x],ls[y],l,mid,id);
}
LL query(int x,int y,int l,int r,int id){
if(l==r)return sum[y]-sum[x];
int mid=l+r>>1;
if(id<=mid)return query(ls[x],ls[y],l,mid,id);
else return sum[ls[y]]-sum[ls[x]]+query(rs[x],rs[y],mid+1,r,id);
}
int main(){
scanf("%d",&n);
for(int x,i=1;i<=n;i++){
scanf("%d",&x);
insert(rt[i-1],rt[i],1,1e9,x);
}scanf("%d",&m);int l,r;LL mx,last;
while(m--){
scanf("%d%d",&l,&r);
mx=last=0;
while(1){
mx=query(rt[l-1],rt[r],1,1e9,mx+1);
if(mx==last){printf("%lld\n",mx+1);break;}
last=mx;
}
}return 0;
}