Codeforces Round #6——E. Exposition

题意:

现在有n个数,每个数有高度为h[i]。现在我们要选择一段连续的区间,使得hmax-hmin<=k。

然后求a:是最多能够展出的书本数  b:有几个这样的区间。

思路:

因为数的个数比较多,所以我们很容易想到要用线段树来维护一段区间的最值 。

然后用二分来求区间长度,然后枚举区间。(二分我一开始没有想到,我一开始还想着for两遍,但是肯定T.....)

然后就query一下就好了,因为每个区间的最大值最小值已经求好了。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define maxn 100010
#define inf 99999999
int smax,smin;
int n,k;
int h[maxn];
int st[maxn],end[maxn];
struct node{
	int l,r;
	int lmax,lmin;
}tree[maxn*4];
void pushup(int v){
	int temp=v<<1;
	tree[v].lmax=max(tree[temp].lmax,tree[temp+1].lmax);
	tree[v].lmin=min(tree[temp].lmin,tree[temp+1].lmin);
}
void build(int l,int r,int v){
	tree[v].l=l;
	tree[v].r=r;
	tree[v].lmax=-1;
	tree[v].lmin=inf;
	if(l==r){
		scanf("%d",&h[l]);
		tree[v].lmax=tree[v].lmin=h[l];
		return ;					//不要忘记return!! 
	}
	int mid=(l+r)>>1;
	int temp=v<<1;
	build(l,mid,temp);
	build(mid+1,r,temp+1);
	pushup(v);
}
void query(int l,int r,int v,int cnt){
	if(tree[v].l==l&&tree[v].r==r){
		if(cnt==0){		//说明是取较小值; 
			smin=min(smin,tree[v].lmin);
			return ;
		}
		else{
			smax=max(smax,tree[v].lmax);
			return ;
		}
	}
	int mid=(tree[v].l+tree[v].r)>>1;
	int temp=v<<1;
	if(r<=mid) query(l,r,temp,cnt);
	else if(l>mid) query(l,r,temp+1,cnt);
	else{
		query(l,mid,temp,cnt);
		query(mid+1,r,temp+1,cnt);
	}
}
int judge(int l){
	for(int i=1;i+l-1<=n;i++){
		smax=-1; smin=inf;
		query(i,i+l-1,1,1);
		query(i,i+l-1,1,0);
		if(smax-smin<=k) return 1;
	}
	return 0;
}
int main(){
	scanf("%d%d",&n,&k);
	build(1,n,1);
	int l=1,r=n+1;
	int ans=-1;
	while(l<r){
		int mid=(l+r)>>1;
		if(judge(mid)){
			l=mid+1;
			ans=max(ans,mid);
		}
		else r=mid;
	}
	int cnt=0;
	for(int i=1;i+ans-1<=n;i++){
		smax=-1; smin=inf;
		query(i,i+ans-1,1,1);
		query(i,i+ans-1,1,0);
		if(smax-smin<=k){
			st[cnt]=i;
			end[cnt++]=i+ans-1;
		}
	}
	printf("%d %d\n",ans,cnt);
	for(int i=0;i<cnt;i++) printf("%d %d\n",st[i],end[i]);r
}
/*
3 3
14 12 10
*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值