题意:
h-index为 有h篇论文,引用数超过h 中最大的h。
给出n篇论文的论文引用次数,问如果只有[L,R]的论文的情况下,h-index是多少。
思路:
注意h-index的定义,如果要求[L,R]的h-index,对[L,R]的论文从小排序,令a[L+x]=y,说明有(R-L+1-x)篇论文的引用数大于y,注意到这个判断是单调的,所以可以二分找到满足条件最大的h=(R-L+1-x)。
但是每个区间排序复杂度太高,我们需要的二分信息可以通过可持续化线段树查询得到。
代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <map>
#include <list>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <sstream>
#define pb push_back
#define X first
#define Y second
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pii pair<int,int>
#define qclear(a) while(!a.empty())a.pop();
#define lowbit(x) (x&-x)
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define mst(a,b) memset(a,b,sizeof(a))
#define cout3(x,y,z) cout<<x<<" "<<y<<" "<<z<<endl
#define cout2(x,y) cout<<x<<" "<<y<<endl
#define cout1(x) cout<<x<<endl
#define IOS std::ios::sync_with_stdio(false)
#define SRAND srand((unsigned int)(time(0)))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
using namespace std;
const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;
const ll mod=1e9+7;
const double eps=1e-8;
const int maxn=100005;
const int maxm=3000005;
int n,q,m,tot;
int a[maxn], t[maxn];
int T[maxm], lson[maxm], rson[maxm], c[maxm];
void Init_hash() {
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 tohash(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;
}
//mid表示paper的数量,now表示找到mid篇paper,需要查询第now小的数来确定引用数
bool check(int mid,int now,int ql,int qr){
int pos=query(T[ql],T[qr+1],now);
return t[pos]>=mid;
}
void solve() {
while(~sdd(n,q)) {
tot=0;
for(int i=1; i<=n; i++) {
sd(a[i]);
}
Init_hash();
T[n+1] = build(1,m);
for(int i = n; i ; i--) {
int pos = tohash(a[i]);
T[i] = update(T[i+1],pos,1);
}
for(int i=0; i<q; i++) {
int ql,qr;
sdd(ql,qr);
int l,r,ans=1;
l=1;
r=qr-ql+1;
//注意存在l==r
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid,(qr-ql+2-mid),ql,qr)) {
ans=mid;
l=mid+1;
} else {
r=mid-1;
}
}
printf("%d\n",ans);
}
}
return ;
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#else
// freopen("","r",stdin);
// freopen("","w",stdout);
#endif
solve();
return 0;
}