题目地址:https://www.icpc.camp/contests/6CP5W4knRaIRgU
比赛的时候知道这题是用主席树+二分,可是当时没有学主席树,就连有模板都不敢套,因为代码实在是太长了。
题意:给你一些数字,要求你某些区间中找到一个h-index。
每次查找h-index复杂度不能超过O(n)
h-index的定义是:有最少h个数不小于h,找到最大的h。
分析:假如查询的区间长度为n,那么ans一定是1-n。用二分查找找到一个最大的n即可
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int maxn=1e5+5; struct Tree { int L,R,num; }tree[maxn*20]; int root[maxn]; int cnt; void updata(int x,int &rt,int a,int b) { tree[cnt++]=tree[rt]; rt=cnt-1; tree[rt].num++; if(a==b)return; int mid=(a+b)/2; if(x>=mid+1) updata(x,tree[rt].R,mid+1,b); else updata(x,tree[rt].L,a,mid); } int quer(int a,int b,int k,int s,int o) { if(s==o)return s; int d=tree[tree[b].L].num-tree[tree[a].L].num; int mid=(s+o)/2; if(k<=d) return quer(tree[a].L,tree[b].L,k,s,mid); else return quer(tree[a].R,tree[b].R,k-d,mid+1,o); } int main() { int n,m; while(cin>>n>>m) { cnt=1; for(int i=1;i<=n;i++) { root[i]=root[i-1]; int num; scanf("%d",&num); updata(num,root[i],1,n); } for(int i=1;i<=m;i++) { int l,r; scanf("%d %d",&l,&r); int b=r-l+1,a=1; int mid=(a+b)/2; while(a!=b) { if(quer(root[l-1],root[r],r-l+1-mid,1,n)>=mid+1) a=mid+1; else b=mid; mid=(a+b)/2; } printf("%d\n",a); } } return 0; }