题目链接:https://cn.vjudge.net/problem/HDU-6278
题意:n个数,q个询问,对于每个询问给定【L,R】,求最大的h,使得区间中大于等于h的数字不小于h。
题解:首先主席树把n个数给保存下来,然后二分枚举h,查询区间内大于等于h的数是否大于等于h个即可,复杂度q*log(n)^2
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{
int l,r;
int sum;
}tree[N*20];
int root[N];
int n,q;
int tot;
int update(int pre,int l,int r,int pos,int val)
{
int cur=++tot;
tree[cur]=tree[pre];
tree[cur].sum+=val;
if(l==r) return cur;
int mid=(l+r)>>1;
if(pos<=mid) tree[cur].l=update(tree[pre].l,l,mid,pos,val);
else tree[cur].r=update(tree[pre].r,mid+1,r,pos,val);
// cout<<l<<" * "<<" * "<< r<<" * "<<tree[cur].sum<<endl;
return cur;
}
int query(int pl,int pr,int l,int r,int pos)
{
// cout<<l<<" * "<<r<<endl;
if(pos<=l) return tree[pr].sum-tree[pl].sum;
int mid=(r+l)>>1;
int res=0;
if(pos<=mid) res+=query(tree[pl].l,tree[pr].l,l,mid,pos);
res+=query(tree[pl].r,tree[pr].r,mid+1,r,pos);
// cout<<l<<" "<<r<<" "<<res<<endl;
return res;
}
int main()
{
int x;
int l,r;
int ll,rr,mid;
int ans;
while(~scanf("%d%d",&n,&q))
{
tot=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
// cout<<i<<endl;
root[i]=update(root[i-1],1,n,x,1);
}
while(q--)
{
scanf("%d%d",&l,&r);
ans=0;
ll=0,rr=n;
while(ll<=rr)
{
mid=(rr+ll)>>1;
if(query(root[l-1],root[r],1,n,mid) >= mid)
{
ll=mid+1;
ans=mid;
}
else
{
rr=mid-1;
}
}
printf("%d\n",ans);
}
}
return 0;
}