Just h-index

Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)

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

题意:

给一个数组,题目再给定一些查询,在区间[x, y]中假设有一个数字ans,区间里有ans个数大于等于ans, 问ans是多少。

思路:

一道主席树的题目,因为查询的ans是多少,所以用的二分去查询这个数。

  • 首先就是建个主席树,因为题目中说ai <= n所以在建树的时候就在[1, n]中间建树就行了。
  • 然后就是查询了,如果k在l的左边,那么右边的区间肯定都是大于等于k的所以只要将T[y].sum - T[x].sum就能知道有多少个数比k来的大,然后如果k小于中间值,那么往左子树找,那么右子树肯定就都会大于k的所以直接加就行了。
  • 二分的时候也要注意一下,当得出的数值比,mid小的时候向下找,否则向上找。
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 100010;
struct NODE {
    int l;
    int r;
    int sum;
};
NODE T[maxn * 50];
int root[maxn], a[maxn];
int cnt = 0;
void Updata(int l, int r, int &x, int y, int pos) {
    T[++cnt] = T[y];
    T[cnt].sum++;
    x = cnt;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (mid >= pos) Updata(l, mid, T[x].l, T[y].l, pos);
    else Updata(mid + 1, r, T[x].r, T[y].r, pos);
}
int Query(int l, int r, int x, int y, int k) {
    if (k <= l) return T[y].sum - T[x].sum;
    int mid = (l + r) >> 1;
    if (k <= mid) return Query(l, mid, T[x].l, T[y].l, k) + T[T[y].r].sum - T[T[x].r].sum;
    else return  Query(mid + 1, r, T[x].r, T[y].r, k);
}
int main() {
    int n, m;
    while (scanf("%d %d", &n, &m) != EOF) {
        cnt = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            Updata(1, n, root[i], root[i - 1], a[i]);
        }
        while (m--) {
            int x, y, ans = 0;
            scanf("%d %d", &x, &y);
            int l = 0, r = n;
            while (r - l > 1) {
                int mid = (l + r) >> 1;
                if (Query(1, n, root[x - 1], root[y], mid) < mid) r = mid;
                else l = mid;
            }
            printf("%d\n", l);
        }
    }
    return 0;
}