Problem(M25):The Kth Large-单调栈/线段树

Problem(M25):The Kth Large 

 

Judge Info

  • Memory Limit: 65536KB
  • Case Time Limit: 2000MS
  • Time Limit: 2000MS
  • Judger: Normal

Description

In the P.E. class , n students listed in a line on the playground. However, they are not ordered by their height. As you know, some of them are higher, while others are shorter. In this way, let’s define a function called F,which depend on the height of the ith students. The F of the ith student (we can call it Fi) with height hi is the sum of three parts: The first part is a number 1,which means himself The second part is: counting from the i-1th student to the 1st student until some one is shorter than the ith student. The third part is: counting from the i+1th student to the last student until some one is shorter than the ith student. For example, if the heights of the students are: 2 3 2 4 5 Then F(1)=1+0+4=5,F(2)=1+0+0=1,F(3)=1+2+2=5,F(4)=1+0+1=2,F(5)=1+0+0=1 Now the problem is very simple,just tell me the the kth large one among all the Fi.

Input

The input contains several test cases. The first line contains an integer T(T ≤ 100) denoting the number of test cases. Then T test cases follow. Each of them begins with a line containing two numbers n and k(1 ≤ k≤n ≤ 100000).The next line contains n integers h1,h2,..., hn where 1 ≤ hi ≤ 1000000000 is the height of i th student.

 

Output

For each test case, output the kth large one among all the Fi.

Sample Input

2
5 2
1 2 2 3 3
5 2
2 3 2 4 5

Sample Output

4 
5 

     


题意:

给出n,k,n个数hi

就是n个人,当前的人为第i个时,高度为hi,

先从i-1找到1,直到找到一个比它小的数,记下查找的步数a

然后从i+1开始向右找到n,直到找到另一个比它小的数,记下查找的步数b

然后第i个数的函数值Fi就是a+b+1


n个人有n个F值

求出第k大的F值

1 ≤ hi ≤ 1000000000 ,n and k(1 ≤ k≤n ≤ 100000).

  

 这题应该用单调栈,不能二分,二分找到的是离a[i]最远的比他小的数,而题目要求的是最近的!   


线段树也可以做nlogn


以下 是单调栈代码:

//Problem(M25):The Kth Large

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <set>
#include <vector>
using namespace std;

__int64 tm[200005];
__int64 tm2[200005]; 

__int64 l_ans[200005];
__int64 r_ans[200005];
__int64 tmp[200005]; 
struct node
{
	__int64 x;
	__int64 num;
	node(){}
	node(__int64 a,__int64 b)
	{
		x=a;num=b;
	}
};
node ans[200005];
__int64 res[200005];
stack <node> sb;
stack <node> sb2;
__int64 max(__int64 a,__int64 b)
{return a<b?b:a;}
__int64 cmp(node a,node b)
{
	if (a.x!=b.x)
		return a.x>b.x;
	else
		return a.num>b.num;
}
int main()
{
	__int64 t,n,k;
	scanf("%I64d",&t);
	while(t--)
	{
		scanf("%I64d%I64d",&n,&k);
	while(!sb.empty())
		sb.pop();
	while(!sb2.empty())
		sb2.pop();
	__int64 i;
	//	scanf("%I64d",&n);
	for (i=1;i<=n;i++)
	{
		scanf("%I64d",&tm[i]);
		tm2[n-i+1]=tm[i];
	}
	//****************************************	计算每个数到左边第一个比之小的数的距离	
	l_ans[1]=0;
	sb.push(node(tm[1],1));
	for (i=2;i<=n;i++)
	{
		if (tm[i]>sb.top().x)
			l_ans[i]=i-sb.top().num-1;
		else
		{
			while(!sb.empty()&&tm[i]<=sb.top().x)
				sb.pop();
			if (sb.empty())
				l_ans[i]=i-1;
			else
				l_ans[i]=i-sb.top().num-1;
		}
		sb.push(node(tm[i],i));
	} 
	//****************************************	计算每个数到右边第一个比之小的数的距离		
	r_ans[1]=0;
	sb2.push(node(tm2[1],1));
	for (i=2;i<=n;i++)
	{
		if (tm2[i]>sb2.top().x)
			r_ans[i]=i-sb2.top().num-1;
		else
		{
			while(!sb2.empty()&&tm2[i]<=sb2.top().x)
				sb2.pop();
			if (sb2.empty())
				r_ans[i]=i-1;
			else
				r_ans[i]=i-sb2.top().num-1;
		}
		sb2.push(node(tm2[i],i));
	} 
	
	///**********翻转r_ans
	for (i=1;i<=n;i++)
	{
		tmp[n-i+1]=r_ans[i];
	}
	
	for (i=1;i<=n;i++)
	{
		r_ans[i]=tmp[i];
	}
  
	for (i=1;i<=n;i++)
	{
		res[i]=l_ans[i]+r_ans[i]+1; 
	} 

	sort(res+1,res+1+n);
 
		printf("%d",res[n-k+1]);
 
	printf("\n");
	
	}
	
	return 0;
	
}






以前二分写的错误代码。   不过不了样例【  4 3 2 1】这种

//Problem(M25):The Kth Large

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;

__int64 tm[100005];
__int64 tm2[100005];
__int64 minn[100005];
__int64	r_minn[100005];
__int64 l_dist[100005];
__int64 backup_r_dist[100005];
__int64 r_dist[100005];
__int64 ans[100005];
int main()
{
	__int64 t,n,k;
	scanf("%I64d",&t);
	while(t--)
	{
		__int64 i;
		scanf("%I64d%I64d",&n,&k);
		for (i=1;i<=n;i++)
		{
			scanf("%I64d",&tm[i]);
			tm2[n-i+1]=tm[i];
		}
		
		__int64 min_mark=tm[n];
		minn[n]=tm[n];
		for (i=n-1;i>=1;i--)
		{
			if (tm[i]<min_mark)
				min_mark=tm[i];
			minn[i]=min_mark;
		}
		__int64 it,tmp;
		l_dist[n]=0;	//最后一个数一定为0;
		for (i=1;i<n;i++)
		{
			it=lower_bound(minn+i+1,minn+1+n,tm[i])-(minn);
			if (it==n+1&&n!=i)  //不存在比tm[i]大的数,全部数都比tm[i]小,按题意取最近的,dist=1;
				l_dist[i]=n-i;
			else
			{ 			
				if (it!=i+1)  it--;//防止越界
				if(tm[i]>minn[it])	//存在比tm[i]小的数
				{
					tmp=upper_bound(minn+i+1,minn+1+n,minn[it])-(minn);//找到大于minn[it]的第一个
					tmp--;
					l_dist[i]=tmp-i-1;
				}
				else  //不存在比tm[i]小的数
				{
					l_dist[i]=n-i;
				}
			} 
		}
		
		
		min_mark=tm2[n];
		r_minn[n]=tm2[n];
		for (i=n-1;i>=1;i--)
		{
			if (tm2[i]<min_mark)
				min_mark=tm2[i];
			r_minn[i]=min_mark;
		}
		//__int64 it,tmp;
		backup_r_dist[n]=0;
		for (i=1;i<n;i++)
		{
			it=lower_bound(r_minn+i+1,r_minn+1+n,tm2[i])-(r_minn);
			if (it==n+1)  //不存在比tm2[i]大的数,全都比他小
				backup_r_dist[i]=0;
			else
			{ 
				if (it!=i+1)  it--;//防止越界
				if(tm2[i]>r_minn[it])	//存在比tm2[i]小的数
				{
					tmp=upper_bound(r_minn+i+1,r_minn+1+n,r_minn[it])-(r_minn);//找到大于r_minn[it]的第一个
					tmp--;
					backup_r_dist[i]=tmp-i-1;
				}
				else  
					backup_r_dist[i]=i-1;//不存在比他小的
			} 
		}
		
		for (i=1;i<=n;i++)
		{
			r_dist[n-i+1]=backup_r_dist[i];
		} 
 
		for (i=1;i<=n;i++)
		{
			ans[i]=r_dist[i]+l_dist[i]+1;
		}
		sort(ans+1,ans+1+n);
		printf("%I64d\n",ans[n-k+1]);
	}
	return 0;
	
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值