Just h-index
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0
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
* 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.
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
解题思路:读懂题意之后,直接上莫队。用树状数组维护后缀和(总-前缀和),然后二分答案即可。
当然对于求后缀和部分,可以直接用主席树求,速度更快这样就不用莫队了。
莫队+二分+树状数组
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
using namespace std;
typedef long long int ll;
const int MAXN=100015;
int N,Q;
int a[MAXN];
struct query{
int l;
int r;
int id;
}q[MAXN];
int block[MAXN];
int blocksize;
bool cmp(query a,query b){
if(block[a.l]==block[b.l])
return a.r<b.r;
return block[a.l]<block[b.l];
}
int ans[MAXN];
int tree[MAXN];
int tot=0;
int lowbit(int x){
return x&-x;
}
void add(int x,int C){
for(int i=x;i<=MAXN;i+=lowbit(i)){
tree[i]+=C;
}
}
int sum(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=tree[i];
return ans;
}
bool judge(int x){
// cout<<x<<" "<<tot<<" "<<sum(x-1)<<endl;
if(tot-sum(x-1)-x>=0)
return true;
return false;
}
void solve(){
int l=1;
int r=1;
tot++;
add(a[1],1);
for(int i=0;i<Q;i++){
// cout<<q[i].r<<q[i].r<<endl;
while (q[i].r > r) {
r++;
add(a[r],1);
tot++;
}
while (q[i].r < r){
add(a[r],-1);
r--;
tot--;
}
while (q[i].l > l) {
add(a[l],-1);
l++;
tot--;
}
while (q[i].l < l) {
l--;
add(a[l],1);
tot++;
}
int ll=1,rr=N;
int m;
while(ll<=rr){
m=(ll+rr)/2;
if(judge(m)){
ll=m+1;
}
else
rr=m-1;
}
ans[q[i].id]=rr;
}
}
int main()
{
while(~scanf("%d%d",&N,&Q)){
tot=0;
memset(tree,0,sizeof(tree));
blocksize=sqrt(N);
for(int i=1;i<=N;i++){
scanf("%d",&a[i]);
block[i]=(i-1)/blocksize+1;
}
for(int i=0;i<Q;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q,q+Q,cmp);
solve();
for(int i=0;i<Q;i++)
{
printf("%d\n",ans[i]);
}
}
return 0;
}
主席树+二分
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
using namespace std;
typedef long long int ll;
const int MAXN=100015;
int N,Q;
int sum[MAXN*20];
int ls[MAXN*20];
int rs[MAXN*20];
int T[MAXN];
int tot=0;
void update(int P,int C,int l,int r,int &rt,int lrt){
rt=++tot;
ls[rt]=ls[lrt];
rs[rt]=rs[lrt];
sum[rt]=sum[lrt];
if(l==r){
sum[rt]+=C;
return;
}
int m=(l+r)/2;
if(P<=m)
update(P,C,l,m,ls[rt],ls[lrt]);
else
update(P,C,m+1,r,rs[rt],rs[lrt]);
sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
int query(int L,int R,int l,int r,int rt,int lrt){
if(L<=l&&r<=R){
return sum[lrt]-sum[rt];
}
int m=(l+r)/2;
int ans=0;
if(L<=m)
ans+=query(L,R,l,m,ls[rt],ls[lrt]);
if(R>m)
ans+=query(L,R,m+1,r,rs[rt],rs[lrt]);
return ans;
}
bool judge(int x,int l,int r){
if(query(x,N,1,N,T[l-1],T[r])-x>=0)
return true;
return false;
}
int main()
{
while(~scanf("%d%d",&N,&Q)){
tot=0;
memset(sum,0,sizeof(sum));
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
int a;
for(int i=1;i<=N;i++){
scanf("%d",&a);
update(a,1,1,N,T[i],T[i-1]);
}
int l,r;
for(int i=0;i<Q;i++){
scanf("%d%d",&l,&r);
int ll=1,rr=N;
int m;
while(ll<=rr){
m=(ll+rr)/2;
if(judge(m,l,r)){
ll=m+1;
}
else
rr=m-1;
}
printf("%d\n",rr);
}
}
return 0;
}