hdu 6278 Just h-index (主席树+二分判断)

原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=6278
题意:就是给你一个区间,让你求一个最大的h,使得在这个区间里面有h个数大于等于h
思路:二分枚举这个h的值,具体看代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int n, q, m;
const int maxn = 250005;
int a[maxn], t[maxn], rt[maxn];
// rt是主席树节点
struct node {
    int l, r, cnt;
} tree[maxn * 20];
int tot = 0;
void updata(int l, int r, int c, int &cur, int x) {//因为用了cur的引用,所以不需要不build函数
    cur = ++tot;
    tree[cur] = tree[c];
    tree[cur].cnt++;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(mid >= x)updata(l, mid, tree[c].l, tree[cur].l, x);
    else updata(mid + 1, r, tree[c].r, tree[cur].r, x);
}
int query(int l, int r, int pre, int rt, int k) { //求区间第k大
    if(l == r) return l;
    int sum = tree[tree[rt].r].cnt - tree[tree[pre].r].cnt;
    int mid = (l + r) >> 1;
    if(sum >= k) return query(mid + 1, r, tree[pre].r, tree[rt].r, k);
    else return query(l, mid, tree[pre].l, tree[rt].l, k - sum);
}
int main() {
    while(~scanf("%d%d", &n, &q)) {
        tot = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            t[i] = a[i];
        }
        sort(t + 1, t + 1 + n);
        int m = unique(t + 1, t + 1 + n) - t - 1;
        for(int i = 1; i <= n; i++) {
            a[i] = lower_bound(t + 1, t + 1 + m, a[i]) - t;
        }
        for(int i = 1; i <= n; i++) {
            updata(1, m, rt[i - 1], rt[i], a[i]);
        }

        while(q--) {
            int l, r;
            scanf("%d%d", &l, &r);
            int left = 1;
            int right = r-l+1;
            //求区间第h大
            int num = 0;
            int ans = 0;
            while(left <= right) {
                int h = (left + right) >> 1;
                num = query(1, m, rt[l - 1], rt[r], h);
                //num 表示区间第h大是哪个数
                /*
                转化思路:只要区间第h大的值大于等于h,说明
                在这个区间里至少有h个数的值大于等于h
                */
                if(t[num] >= h) {
                    ans = h;
                    left = h + 1;
                } else {
                    right = h - 1;
                    ans = h - 1;
                }
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/80708850
今日推荐