题目:
题解:
如果[1,x]可以取到,我们加入一个数y,如果y<=x+1,那么我们有新的取数集合[1,x+y];如果y>x+1,那么x+1还是取不到啊,这样我们就有了一个暴力的思路
进一步考虑,对于一个还未发展的数列,我们的取值范围是[1,x],x=0,ans=1,我们可以把权值<=ans的数字加起来,和设为y
如果这时ans<=y,就是说除了凑成[1,x]的数外,我们还能找出一个数<=ans,这样取数集合是[1,y];
如果这时ans>y,就是说除了凑成[1,x]的数外,我们找不出任何一个数字了,这样取数集合是[1,x],ans就取不到咯
我们可以依据这种方法求ans,建一棵权值线段树,要维护区间和的话,用主席树就好啦
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=100005;
int sz,root[N],b[N],a[N],p[N];
struct hh{int l,r,w,sum;}t[N*20];
void insert(int &now,int l,int r,int x,int v)
{
t[++sz]=t[now]; now=sz;
t[now].w++; t[now].sum+=v;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) insert(t[now].l,l,mid,x,v);
else insert(t[now].r,mid+1,r,x,v);
}
int qurry(int x,int y,int l,int r,int lrange,int rrange)
{
if (rrange<lrange) return 0;
if (lrange<=l && rrange>=r) return t[y].sum-t[x].sum;
int mid=(l+r)>>1,ans=0;
if (lrange<=mid) ans+=qurry(t[x].l,t[y].l,l,mid,lrange,rrange);
if (rrange>mid) ans+=qurry(t[x].r,t[y].r,mid+1,r,lrange,rrange);
return ans;
}
int main()
{
int s=0,n,maxx=0,m;
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),maxx+=a[i],b[++s]=a[i];
sort(b+1,b+s+1);
s=unique(b+1,b+s+1)-b-1;
for (int i=1;i<=n;i++) p[i]=lower_bound(b+1,b+s+1,a[i])-b;
for (int i=1;i<=n;i++)
{
root[i]=root[i-1];
insert(root[i],1,s,p[i],b[p[i]]);
}
scanf("%d",&m);
while (m--)
{
int x,y,ans=1;
scanf("%d%d",&x,&y);
while (1)
{
int t=qurry(root[x-1],root[y],1,s,1,upper_bound(b+1,b+s+1,ans)-b-1);
if (t>=ans) ans=t+1;
else break;
}
printf("%d\n",ans);
}
}