HDU 6278 - Just h-index - [莫队算法+树状数组+二分][2018JSCPC江苏省赛C题]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6278
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)
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.
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.
## 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.
题意:
一个作者它的“h-index”指的是:有一个最大的正整数h,且满足他有至少h篇论文的引用量不低于h。
现在给出n篇论文的引用量,m个区间[L,R]的查询,询问假设他只发了[L,R]这个区间内的这些论文,则他的h-index为多少。
题解:
当初比赛的时候不会主席树,也不会莫队,只能拿着普通的线段树在那里硬刚,结果十分凄惨。
现在会了分块版的莫队算法,回来补题了。
考虑num[c]表示引用量为c的文章数,那么用树状数组维护就可以 $O\left( {\log _2 N} \right)$ 的进行单点修改、区间查询,正好符合题目要求;
所以我们每次区间转移进行 $O\left( {\log _2 N} \right)$ 的进行单点修改,
然后转移结束之后,当前区间的答案(h_index)就可以通过 二分查找 + $O\left( {\log _2 N} \right)$ 的区间查询 得到。
时间复杂度大概在 $O\left( {N \cdot \sqrt N \cdot \left( {\log _2 N} \right)^2 } \right)$,从理论上讲应该可以过。
AC代码:
#include<bits/stdc++.h> using namespace std; const int MAXN=1e5+10; const int MAXM=1e5+10; int n,m; int citation[MAXN]; int h_idx[MAXM]; struct Query { int block; int id; int l,r; bool operator <(const Query &oth) const { if(block==oth.block) return r<oth.r; return block<oth.block; } }query[MAXM]; struct _BIT{ int N,C[MAXN]; int lowbit(int x){return x&(-x);} void init(int n)//初始化共有n个点 { N=n; for(int i=1;i<=N;i++) C[i]=0; } void add(int pos,int val)//在pos点加上val { while(pos<=N) { C[pos]+=val; pos+=lowbit(pos); } } int sum(int pos)//查询1~pos点的和 { int ret=0; while(pos>0) { ret+=C[pos]; pos-=lowbit(pos); } return ret; } }BIT; int main() { while(scanf("%d%d",&n,&m)!=EOF) { int len=sqrt(n); for(int i=1;i<=n;i++) scanf("%d",&citation[i]); for(int i=1;i<=m;i++) { scanf("%d%d",&query[i].l,&query[i].r); query[i].block=query[i].l/len; query[i].id=i; } sort(query+1,query+m+1); BIT.init(n); int pl=1; int pr=0; int cnt=0; for(int i=1;i<=m;i++) { if(pr<query[i].r) { for(int j=pr+1;j<=query[i].r;j++) { BIT.add(citation[j],1); cnt++; } } if(pr>query[i].r) { for(int j=pr;j>query[i].r;j--) { BIT.add(citation[j],-1); cnt--; } } if(pl<query[i].l) { for(int j=pl;j<query[i].l;j++) { BIT.add(citation[j],-1); cnt--; } } if(pl>query[i].l) { for(int j=pl-1;j>=query[i].l;j--) { BIT.add(citation[j],1); cnt++; } } pl=query[i].l; pr=query[i].r; int l=1,r=n,mid; while(l<r) { mid=(l+r+1)/2; if(cnt-BIT.sum(mid-1)<mid) r=mid-1; else l=mid; } h_idx[query[i].id]=r; } for(int i=1;i<=m;i++) printf("%d\n",h_idx[i]); } }