Just h -indexTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 442 Accepted Submission(s): 205 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 . Input The input consists of several test cases and is terminated by end-of-file. Output For each question, print an integer which denotes the answer. 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 Source |
大致题意:给你一个序列,然后给你很多个询问,每个询问让你求给定区间[l,r]中,最大的h,使得区间中大于等于h的数字不小于h。
湘潭邀请赛现场的题目。当时听了题目,没仔细想别的方法,就用莫队算法硬刚,运气不错算是过了。现在看来,这是一道可持久化线段树的好题。
首先,这里的数字都是1~n之间的,所以我们可以按照数字的大小插入线段树,每个点维护对应数字出现的次数和对应区间的数字和。然后,因为有区间操作,所以加上可持久化操作,每一次都是右端点对应线段树减去左端点对应线段树。那么问题的关键就是怎么求这个最大的h。这个h的大小无非就是二分答案的去尝试,但是这里我们不需要在线段树外面套一个二分,直接在线段树里面二分即可。因为线段树本身的范围就是1~n,每次从根往下走的过程其实就是二分区间不断缩小的过程,只不过是改一下这个往下走的方向。判断往哪走的条件显然就是这个h的判断条件,如果对于当前mid,区间内比它大的数字个数小于mid,那么往左子树走,否则往右子树走。在走的过程中,同时记录一个当前区间右边的数字个数,这样已知往下走,最后返回满足条件的点即可。具体见代码:
#include<bits/stdc++.h>
#define LL long long
#define N 150010
using namespace std;
int a[N],rt[N<<4];
struct Persistent_SegTree
{
struct node{int l,r,sum;} T[N<<4];
int cnt; void init(){cnt=0;}
void build(int &i,int l,int r)
{
i=++cnt;
T[i]=node{0,0,0};
if (l==r) return;
int mid=(l+r)>>1;
build(T[i].l,l,mid);
build(T[i].r,mid+1,r);
}
void ins(int &i,int old,int l,int r,int x)
{
i=++cnt;
T[i]=T[old];
T[i].sum++;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) ins(T[i].l,T[old].l,l,mid,x);
else ins(T[i].r,T[old].r,mid+1,r,x);
}
int query(int i,int j,int k,int l,int r)
{
if (l==r) return l;
int mid=(l+r)>>1;
int sum=T[j].sum-T[i].sum;
int t=sum-T[T[j].l].sum+T[T[i].l].sum;
if (t<mid+1-k) return query(T[i].l,T[j].l,k+t,l,mid);
else return query(T[i].r,T[j].r,k,mid+1,r);
}
} Persist;
int main()
{
int n,q,T_T;
while(~scanf("%d%d",&n,&q))
{
Persist.init();
Persist.build(rt[0],1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
Persist.ins(rt[i],rt[i-1],1,n,a[i]);
}
for(int i=1;i<=q;i++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",Persist.query(rt[l-1],rt[r],0,1,n));
}
}
return 0;
}