2018湖南湘潭CCPC邀请赛 && HDU6278: C. Just h-index(主席树)

 

Just h-index

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 548    Accepted Submission(s): 256

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

 

题意:给你n个数,m次查询, 每次求一个最大的m满足:在这个区间中有至少m个数大于等于m

 

因为每个数都≤n,所以不用离散化直接按权值建主席树

模板题,就是求区间第k大稍微变一下下(模板改一行)

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n, m, tot, t[100005], a[100005];
typedef struct
{
	int l, r;
	int size;
}Ctree;
Ctree s[3233333];
int Build(int l, int r);
int Update(int root, int x);
int Query(int lx, int rx);
int main(void)
{
	int i, l, r;
	while(scanf("%d%d", &n, &m)!=EOF)
	{
		tot = 0;
		for(i=1;i<=n;i++)
			scanf("%d", &a[i]);
		t[0] = Build(1, n);
		for(i=1;i<=n;i++)
			t[i] = Update(t[i-1], a[i]);
		while(m--)
		{
			scanf("%d%d", &l, &r);
			printf("%d\n", Query(t[l-1], t[r]));
		}
	}
	return 0;
}

int Build(int l, int r)
{
	int m, root;
	root = ++tot;
	m = (l+r)/2;
	s[root].size = 0;
	if(l==r)
		return root;
	s[root].l = Build(l, m);
	s[root].r = Build(m+1, r);
	return root;
}

int Update(int root, int x)
{
	int now, tmp, l, r, m;
	tmp = now = ++tot;
	l = 1, r = n;
	while(l<r)
	{
		s[now].size = s[root].size+1;
		m = (l+r)/2;
		if(x<=m)
		{
			s[now].l = ++tot;
			s[now].r = s[root].r;
			root = s[root].l;
			now = tot;
			r = m;
		}
		else
		{
			s[now].l = s[root].l;
			s[now].r = ++tot;
			root = s[root].r;
			now = tot;
			l = m+1;
		}
	}
	s[now].size = s[root].size+1;
	return tmp;
}

int Query(int lx, int rx)
{
	int l, r, m, now;
	l = 1, r = n;
	now = 0;
	while(l<r)
	{
		m = (l+r)/2;
		if(s[s[rx].r].size-s[s[lx].r].size+now<=m)
		{
			r = m;
			now += s[s[rx].r].size-s[s[lx].r].size;
			lx = s[lx].l;
			rx = s[rx].l;
		}
		else
		{
			l = m+1;
			lx = s[lx].r;
			rx = s[rx].r;
		}
	}
	return r;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值