Just h-index
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 339 Accepted Submission(s): 154
Bobo has published n papers with citations a1,a2,…,an respectively.
One day, he raises q questions. The i-th question is described by two integers li and ri, asking the h-index of Bobo if has *only* published papers with citations ali,ali+1,…,ari.
The first line of each test case contains two integers n and q.
The second line contains n integers a1,a2,…,an.
The i-th of last q lines contains two integers li and ri.
## Constraint
* 1≤n,q≤105
* 1≤ai≤n
* 1≤li≤ri≤n
* The sum of n does not exceed 250,000.
* The sum of q does not exceed 250,000.
/*
题目意思:给n个数,q次查询,每次查询问给出的一个区间[l,r],
要求出最大的h,使得在[l,r]这个区间内满足,h个数的值
大于等于h(a1,a2,代表第1篇引用的次数,第2篇引用的次数)
思路:可以借助主席树求出区间第 k 大的值是多少(假设为 x),
那么这个区间中就有len-k+1个数是大于等于x的(len为区间长度),
这样通过二分h,每次判断区间中是否有 h 个数大于 h 即可
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int a[maxn],cnt;
int root[maxn];
vector<int> v;
struct node{
int l,r,sum;
}T[maxn*25];
int getid(int x){
//return 第一个大于等于的值
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
//2.生成线段树
void update(int l,int r,int &x,int y,int pos){
T[++cnt]=T[y];
T[cnt].sum++;
x=cnt; //修改root[i]所指的根节点
if(l==r) return ; //更新完成
int mid = (l+r)>>1;
//在左子树
if(mid >= pos) update(l,mid,T[x].l,T[y].l,pos);
else update(mid+1 ,r ,T[x].r,T[y].r,pos);
}
int query(int l, int r,int x, int y,int val){
if(l==r) return l; //查询成功
int mid = (l+r)>>1;
int sum = T[T[y].l].sum - T[T[x].l].sum;
if(sum >= val ) return query(l,mid,T[x].l,T[y].l,val);
else return query(mid+1 ,r ,T[x].r,T[y].r,val-sum);
}
int main(){
int t,n,m,l,r,p;
while(~scanf("%d%d",&n,&m)){
cnt=0;
v.clear();
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
v.push_back(a[i]);
}
//1.去重
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++) update(1,n,root[i],root[i-1],getid(a[i]));
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
int len=r-l+1;
int lb=1,rb=len,ans=0;
while(lb<=rb){ //二分答案
int h=(lb+rb)>>1; //h篇
int k=len-h+1; //第k小,(相当于第h大)
int id=query(1,n,root[l-1],root[r],k);
if(v[id-1]>=h){ //查看第h大的引用次数是否大于等于h
ans=max(ans,h); //说明有h篇引用次数大于 v[第h大]
lb=h+1; //可能有大于h的情况
}else{
rb=h-1;
}
}
printf("%d\n",ans);
}
}
}