HDU - 2665 Kth number(划分树模板题)

50 篇文章 0 订阅
17 篇文章 0 订阅

Kth number

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12101    Accepted Submission(s): 3692


Problem Description
Give you a sequence and ask you the kth big number of a inteval.
 

Input
The first line is the number of the test cases.
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.
The second line contains n integers, describe the sequence.
Each of following m lines contains three integers s, t, k.
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]
 

Output
For each test case, output m lines. Each line contains the kth big number.
 

Sample Input
  
  
1 10 1 1 4 2 3 5 6 7 8 9 0 1 3 2
 

Sample Output
  
  
2
 

Source
 

Recommend
zty
 

题目大意:在一个含有N个数字的数组中,询问某个区间内的第K大,然后输出
解题思路:这是一个标准的划分树的板子,划分树用来解决区间的第K大问题,主要是通过将数组排序后,将未排序的数组按照平分的方式,小的在左边,大的在右边,同时,标记在当前位置之前有多少在左边,然后log级别去查询
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long LL;

int deep[20][100005];
int sorted[100005];
int son[20][100005];
void build(int l,int r,int de)
{
	if(l == r)
		return;
	int mid = (l + r)/2;
	int pos = mid - l + 1;
	for(int i = l;i <= r;i++)
		if(deep[de][i] < sorted[mid])
			pos--;
	int lpos = l;
	int rpos = mid + 1;
	for(int i=l;i<=r;i++)
	{
		if(deep[de][i]<sorted[mid])
			deep[de+1][lpos++]=deep[de][i];
		else if(deep[de][i] == sorted[mid]&&pos>0)
		{
			pos--;
			deep[de+1][lpos++]=deep[de][i];
		}
		else
			deep[de+1][rpos++]=deep[de][i];
		son[de][i]=son[de][l-1] + lpos-l;
	}
	build(l,mid,de+1);
	build(mid+1,r,de+1);
}
int query(int L,int R,int l,int r,int de,int K)
{
	int newl,newr;
	if(l == r)
		return deep[de][l];
	int mid = (L + R) / 2;
	int cnt = son[de][r] - son[de][l-1];
	if(cnt >= K)
	{
		newl = L + son[de][l-1] - son[de][L-1];//左边不在所查询区间的个数+L
		newr = newl + cnt - 1;
		return query(L,mid,newl,newr,de+1,K);//每层的操作是一半一半进行的,所以在大区间[L,R]时候根据cnt的大小边界取mid
	}
	else
	{
		newr = r + son[de][R] - son[de][r];
		newl = newr - (r - l - cnt);
		return query(mid+1,R,newl,newr,de+1,K-cnt);
	}
}
int main()
{
	int T,n,q,i,l,r,cnt;
	cin>>T;
	while(T--)
	{
		cin>>n>>q;
		memset(sorted,0,sizeof(sorted));
		memset(deep,0,sizeof(deep));
		memset(son,0,sizeof(son));
		for(i=1;i<=n;i++)
		{
			cin>>deep[0][i];
			sorted[i]=deep[0][i];
		}
		sort(sorted+1,sorted+1+n);
		build(1,n,0);
		while(q--)
		{
			cin>>l>>r>>cnt;
			cout<<query(1,n,l,r,0,cnt)<<endl;//表示长度,区间,层数,第几大
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值