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)

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

题意:

一个作者它的“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]);
    }
}

原文地址:https://www.cnblogs.com/dilthey/p/9235907.html

时间: 2024-10-06 08:17:02

HDU 6278 - Just h-index - [莫队算法+树状数组+二分][2018JSCPC江苏省赛C题]的相关文章

【bzoj3289】Mato的文件管理 离散化+莫队算法+树状数组

原文地址:http://www.cnblogs.com/GXZlegend/p/6805224.html 题目描述 Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号.为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问.Mato每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料.Mato有一个习惯,他总是从文件大小从小到大看资料.他先把要看的文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序.排

BZOJ 3289:Mato的文件管理(莫队算法+树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=3289 题意:…… 思路:求交换次数即求逆序对数.确定了这个之后,先离散化数组.然后在后面插入元素的话,就是在区间里面找比它大的元素数量,在前面插入元素的话,就是在区间里面找比它小的元素数量.删除操作类似.因为排序是从小到大排序,所以要找比它大的数量就是区间长度减去小于等于该元素的数量,所以是(R - L + 1 - sum(a[i])),要找比它小的数量就是(sum(a[i] - 1)).然后用莫

【BZOJ3289】Mato的文件管理 莫队算法+树状数组

[BZOJ3289]Mato的文件管理 Description Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号.为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问.Mato每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料.Mato有一个习惯,他总是从文件大小从小到大看资料.他先把要看的文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序.排序程序可以在1单位时间内交换2个相邻的文件(因为加密

BZOJ 3289: Mato的文件管理[莫队算法 树状数组]

3289: Mato的文件管理 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 2399  Solved: 988[Submit][Status][Discuss] Description Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号.为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问.Mato每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料.Mat

【BZOJ】3289: Mato的文件管理(莫队算法+树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=3289 很裸的莫队... 离线了区间然后分块排序后,询问时搞搞就行了. 本题中,如果知道$[l, r]$后,考虑如何转移$[l, r+1]$,发现就是$a[r+1]$的颜色在这个区间的排名,然后$r-l+1-排名$就是需要移动的次数. 那么本题中因为只需要裸的排名,所以可以考虑用bit,即离散后搞. 然后就行了 #include <cstdio> #include <cstdio> #

BZOJ 2120: 数颜色 带修改的莫队算法 树状数组套主席树

https://www.lydsy.com/JudgeOnline/problem.php?id=2120 标题里是两种不同的解法. 带修改的莫队和普通莫队比多了个修改操作,影响不大,但是注意一下细节不要出现zz错误. 这道题修改的数量比较少可以写莫队,但是如果修改数量多或者是特别极限的数据大概是不行的吧. 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstrin

[bzoj3289]Mato的文件管理_莫队_树状数组

Mato的文件管理 bzoj-3289 题目大意:给定一个n个数的序列.m次询问:一段区间中的逆序对个数. 注释:$1\le n\,mle 5\cdot 10^4$. 想法: 开始想这个题的大佬们,给您点儿提示吧:$O(nlogn\sqrt(n))$可过哦! 所以这个题就是莫队的裸题了. 我们的莫队上的区间在动的时候随时更新树状数组上的信息即可.. 然后碰见了一整块区间,我们就直接求逆序对即可, 最后,附上丑陋的代码... ... #include <iostream> #include &l

Chika and Friendly Pairs(莫队+离散化+树状数组)

Chika and Friendly Pairs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1164    Accepted Submission(s): 421 Problem Description Chika gives you an integer sequence a1,a2,…,an and m tasks. For

HDU 2852 KiKi&#39;s K-Number (树状数组 &amp;&amp; 二分)

题意:给出对容器的总操作次数n, 接下来是这n个操作.这里对于一个容器提供三种操作, 分别是插入.删除和查找.输入0  e表示插入e.输入1  e表示删除e,若元素不存在输出No Elment!.输入2  e  k表示查找比e大且第k大的数, 若不存在则输出Not Find! 分析:这里考虑树状数组做的原因是在第三个操作的时候, 只要我们记录了元素的总数, 那通过求和操作, 便能够高效地知道到底有多少个数比现在求和的这个数要大, 例如 tot - sum(3)就能知道整个集合里面比3大的数到底有