原题 (吐槽一下题目描述非常绕口)
下面粘贴的格式不太好,参考pdf或者原题链接:
比赛题目:
http://acm.hdu.edu.cn/downloads/2018ccpc_hn.pdf
The hh-index of an author is the largest hh where he has at least hh papers with citations not less than hh.
Bobo has published nn papers with citations a1,a2,…,ana1,a2,…,an respectively.
One day, he raises qq questions. The ii-th question is described by two integers lili and riri, asking the hh-index of Bobo if has *only* published papers with citations ali,ali+1,…,ariali,ali+1,…,ari.
Input
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains two integers nn and qq.
The second line contains nn integers a1,a2,…,ana1,a2,…,an.
The ii-th of last qq lines contains two integers lili and riri.
Output
For each question, print an integer which denotes the answer.
## Constraint
* 1≤n,q≤1051≤n,q≤105
* 1≤ai≤n1≤ai≤n
* 1≤li≤ri≤n1≤li≤ri≤n
* The sum of nn does not exceed 250,000250,000.
* The sum of qq does not exceed 250,000250,000.
Sample Input
5 3
1 5 3 2 1
1 3
2 4
1 5
5 1
1 2 3 4 5
1 5
Sample Output
2
2
2
3
题目大意:
在一个区间内求一个h,h满足区间内至少有h个数大于等于h
二分h(1到区间长度len),对于每个h检查是不是有h个大于等于它,也就是看看第h大是不是大于等于它 ,所以用主席树查询区间第k大的数
AC代码
#include <bits/stdc++.h>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=2e5+5e4+10;
const int M=maxn*100;
int n,q,m,tot;
int a[maxn],t[maxn];
int T[maxn],lson[M],rson[M],c[M];
void init_hs(){
for(int i=1;i<=n;i++)
t[i]=a[i];
sort(t+1,t+1+n);
m=unique(t+1,t+1+n)-t-1;
}
int build(int l,int r){
int root = tot++;
c[root]=0;
if(l!=r){
int mid=(l+r)>>1;
lson[root]=build(l,mid);
rson[root]=build(mid+1,r);
}
return root;
}
int hs(int x){
return lower_bound(t+1,t+1+m,x)-t;
}
int update(int root ,int pos,int val){
int newroot=tot++,tmp=newroot;
c[newroot]=c[root]+val;
int l=1,r=m;
while(l<r){
int mid=(l+r)>>1;
if(pos<=mid){
lson[newroot]=tot++;
rson[newroot]=rson[root];
newroot=lson[newroot];
root=lson[root];
r=mid;
}
else{
rson[newroot]=tot++;
lson[newroot]=lson[root];
newroot=rson[newroot];
root=rson[root];
l=mid+1;
}
c[newroot]=c[root]+val;
}
return tmp;
}
int query(int left_root,int right_root,int k){
int l=1,r=m;
while(l<r){
int mid=(l+r)>>1;
if(c[lson[left_root]]-c[lson[right_root]]>=k){
r=mid;
left_root=lson[left_root];
right_root=lson[right_root];
}
else{
l=mid+1;
k-=c[lson[left_root]]-c[lson[right_root]];
left_root=rson[left_root];
right_root=rson[right_root];
}
}
return l;
}
inline int check(int num,int x){
if(num<=x){
return 1;
}else{
return 0;
}
}int number[maxn];//元数据存档
int main()
{
#ifndef ONLINE_JUDGE
freopen("r.txt","r",stdin);
#endif
while(scanf("%d%d",&n,&q)!=EOF){
tot=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
init_hs();
T[n+1]=build(1,m);
for(int i=n;i;i--){
int pos=hs(a[i]);
T[i]=update(T[i+1],pos,1);
}
int tmp;
while(q--){
int x,y,l,r,mid;
int t1,t2;
scanf("%d%d",&x,&y);
int len=y-x+1;
l=1;
r=len; //h只能在1到len之间。
while(l<r){
mid=(l+r)>>1;
t1=t[query(T[x],T[y+1],len-mid+1)];
t2=t[query(T[x],T[y+1],len-(mid+1)+1)]; //二分h,对于每个h(mid)检查是不是有h个大于等于它,也就是看看第h大是不是大于等于它
if(check(mid,t1)){
if(check(mid+1,t2)){
l=mid+1;
}
else{
l=mid;
break;
}
}else{
r=mid-1;
}
}
printf("%d\n",l);
}
}
return 0;
}