程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> poj2104 K

poj2104 K

編輯:關於C++

 

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 43988   Accepted: 14569 Case Time Limit: 2000MS

 

Description

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.

Input

The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).

Output

For each question output the answer to it --- the k-th number in sorted a[i...j] segment.

Sample Input

7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

Sample Output

5
6
3

Hint

This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.

Source

Northeastern Europe 2004, Northern Subregion

 

 

 

有沒有覺得題目很熟悉啊?是不是感覺和poj2761很像啊?不過這道題稍微麻煩一點,區間之間存在包含關系,所以就不能用排序+平衡樹做了。

這道題的正確解法是劃分樹(可用於求區間第k小數,復雜度log(n))。劃分樹是一種基於線段樹的數據結構,基本思想是對於一個區間,將它劃分成兩個區間,左區間的數全部小於等於右區間的數,分別對應左右子樹。構建劃分樹時要記錄到達某個位置時進入左子樹的數的個數num,查詢時就可以通過num確定下一個查詢區間,最後將區間范圍縮小到1,也就找到了答案。(詳見代碼…)


 

 

 

#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define pa pair
#define MAXN 100005
using namespace std;
int n,m,a[MAXN],val[20][MAXN],num[20][MAXN];
inline int read()
{
	int ret=0,flag=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') flag=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
	return ret*flag;
}
inline void build(int l,int r,int x)
{
	if (l==r) return;
	int mid=(l+r)>>1,lsame=mid-l+1,same=0,ln=l,rn=mid+1;
	F(i,l,r) if (val[x][i]a[mid]) val[x+1][rn++]=val[x][i];
		else
		{
			if (lsame>=++same) num[x][i]++,val[x+1][ln++]=val[x][i];
			else val[x+1][rn++]=val[x][i];
		}
	}
	build(l,mid,x+1);
	build(mid+1,r,x+1);
}
inline int query(int st,int ed,int k,int l,int r,int x)
{
	if (l==r) return val[x][l];
	int lx,ly,rx,ry,mid=(l+r)>>1;
	if (st==l) lx=0,ly=num[x][ed];
	else lx=num[x][st-1],ly=num[x][ed]-lx;
	if (ly>=k)
	{
		st=l+lx;ed=st+ly-1;
		return query(st,ed,k,l,mid,x+1);
	}
	else
	{
		rx=st-l-lx;ry=ed-st+1-ly;
		st=mid+1+rx;ed=st+ry-1;
		return query(st,ed,k-ly,mid+1,r,x+1);
	}
}
int main()
{
	n=read();m=read();
	F(i,1,n) val[0][i]=a[i]=read();
	sort(a+1,a+n+1);
	build(1,n,0);
	F(i,1,m)
	{
		int x=read(),y=read(),k=read();
		printf("%d\n",query(x,y,k,1,n,0));
	}
}


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved