HDU 6278 Just h -index(可持久化线段树)

Just h -index

Time 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 .

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

 

Source

CCPC2018-湖南全国邀请赛-重现赛(感谢湘潭大学)

大致题意:给你一个序列,然后给你很多个询问,每个询问让你求给定区间[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;
}

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/81196282
今日推荐