HDU 6278 Just h-index (二分答案+主席树)

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


Problem Description
The  h-index of an author is the largest  h where he has at least  h papers with citations not less than  h.

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.
 

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  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.
 

Output
For each question, print an integer which denotes the answer.

## Constraint

1n,q105
1ain
1lirin
* The sum of  n does not exceed  250,000.
* The sum of  q does not exceed  250,000.
 

Sample Input
 
  
5 31 5 3 2 11 32 41 55 11 2 3 4 51 5
 

Sample Output
 
  
2223
 

/*
题目意思:给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);

}

猜你喜欢

转载自blog.csdn.net/rvelamen/article/details/80754828