HDU - 2665 Kth number(劃分樹模板題)

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;
}


發佈了149 篇原創文章 · 獲贊 5 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章