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): 228    Accepted Submission(s): 107


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

1n,q105
1ain
1lirin
* The sum of  n does not exceed  250,000.
* The sum of  q does not exceed  250,000.
 

Sample Input
 
 
5 31 5 3 2 11 32 41 55 11 2 3 4 51 5
 

Sample Output
 
 
2223
 

Source
 

Recommend
liuyiding
 

题解:


一种二分枚举 citations(mid)

再求出[mid,n]的和,即大于等于mid有多少篇论文cnt.主席树的查询操作O(logn)

然后判断cnt是否大于等于mid,进行二分

时间复杂度: O(n*logn + q*logn*logn)

代码:

//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
int arr[maxn];
int root[maxn],tot;
inline void init() {
    memset(root,0,sizeof(root));
    tot = 0;
}
struct SegTree
{
    int lson[maxn<<5],rson[maxn<<5],sum[maxn<<5];
    void init() {
        memset(lson,0,sizeof(lson));
        memset(rson,0,sizeof(rson));
        memset(sum,0,sizeof(sum));
    }
    void push_up(int rt) {
        sum[rt] = sum[lson[rt]] + sum[rson[rt]];
    }
    void build(int l,int r,int& rt) {
        rt = ++tot;
        if(l == r) {
            sum[rt] = 0;
            return;
        }
        int mid = (l+r)>>1;
        build(l,mid,lson[rt]);
        build(mid+1,r,rson[rt]);
        push_up(rt);
    }
    void update(int pos,int val,int l,int r,int ord,int &rt) {
        rt = ++tot;
        lson[rt] = lson[ord];
        rson[rt] = rson[ord];
        if(l == r) {
            sum[rt] = sum[ord] + val;///
            return;
        }
        int mid = (l+r)>>1;
        if(pos <= mid) update(pos,val,l,mid,lson[ord],lson[rt]);
        else update(pos,val,mid+1,r,rson[ord],rson[rt]);
        push_up(rt);
    }
    int query(int pos,int l,int r,int lrt,int rrt) {
        if(l == r) return sum[rrt] - sum[lrt];
        int mid = (l + r) >> 1;
        if(pos <= mid)return sum[rson[rrt]] - sum[rson[lrt]] + query(pos,l,mid,lson[lrt],lson[rrt]); 
        return query(pos,mid+1,r,rson[lrt],rson[rrt]);
    }
}seg;
int main()
{
    int n,q;
    while(~scanf("%d%d",&n,&q))
    {
        init();
        //seg.init();
        seg.build(1,n,root[0]);
        //printf("%d %d %d\n",root[0],seg.lson[root[0]],seg.rson[root[0]]);
        for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
        for(int i=1;i<=n;i++) seg.update(arr[i],1,1,n,root[i-1],root[i]);
        while(q--) 
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int l = 0,r = inf;
            while(l<=r) {
                int mid = (l+r) >> 1;
                int ans = seg.query(mid,1,n,root[x-1],root[y]);
                if(ans >= mid) l = mid + 1;
                else r = mid - 1; 
            }
            printf("%d\n",r);
        }
    }
    return 0;
}


我们可以发现这个二分其实是没有必要的.

在主席树的查询操作中我们就可以二分出其位置

时间复杂度 O((n+q)logn)

代码:

//#include<bits/stdc++.h>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#include<iostream>  
#include<vector>  
using namespace std;  
const int maxn = 1e5+10;  
int arr[maxn];  
int root[maxn],tot;  
inline void init() {  
    memset(root,0,sizeof(root));  
    tot = 0;  
}  
struct SegTree  
{  
    int lson[maxn<<5],rson[maxn<<5],sum[maxn<<5];  
    void push_up(int rt) {  
        sum[rt] = sum[lson[rt]] + sum[rson[rt]];  
    }  
    void build(int l,int r,int& rt) {  
        rt = ++tot;  
        if(l == r) {  
            sum[rt] = 0;  
            return;  
        }  
        int mid = (l+r)>>1;  
        build(l,mid,lson[rt]);  
        build(mid+1,r,rson[rt]);  
        push_up(rt);  
    }  
    void update(int pos,int val,int l,int r,int ord,int &rt) {  
        rt = ++tot;  
        lson[rt] = lson[ord];  
        rson[rt] = rson[ord];  
        if(l == r) {  
            /// sum[rt] += val; 唔!这里有个Bug,还好比赛前发现了  
            sum[rt] = sum[ord] + val;  
            return ;  
        }  
        int mid = (l+r)>>1;  
        if(pos <= mid) update(pos,val,l,mid,lson[ord],lson[rt]);  
        else update(pos,val,mid+1,r,rson[ord],rson[rt]);  
        push_up(rt);  
    }  
    /// 直接在主席树中查询其位置
    int query(int l,int r,int pre,int rt,int s) {
        if(l == r) return l;
        int cnt = sum[rson[rt]] - sum[rson[pre]];
        int mid = (l+r)>>1;
        if(mid+1 <= cnt+s) return query(mid+1,r,rson[pre],rson[rt],s);
        return query(l,mid,lson[pre],lson[rt],s+cnt);
    }
}seg;  
int main()  
{  
    int n,q;  
    while(~scanf("%d%d",&n,&q))  
    {  
        init();  
        seg.build(1,n,root[0]);  
        for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
        for(int i=1;i<=n;i++) {  
            seg.update(arr[i],1,1,n,root[i-1],root[i]);  
        }  
        while(q--)   
        {  
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",seg.query(1,n,root[x-1],root[y],0));
        }  
    }  
    return 0;  
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值