【BZOJ4149】[AMPPZ2014]Global Warming 单调栈+RMQ+二分

【BZOJ4149】[AMPPZ2014]Global Warming

Description

给定一个序列a[1],a[2],...,a[n]。请从中选出一段连续子序列,使得该区间最小值唯一、最大值也唯一。

输出选出的子序列的长度的最大值以及取到最大值时左端点的最小值。

Input

第一行包含一个正整数n(1<=n<=500000),表示序列长度。

第二行包含n个正整数,依次表示a[1],a[2],...,a[n](-10^9<=a[i]<=10^9)。

Output

包含一行两个整数l,k,其中l表示选出的子序列的长度的最大值,k表示取到最大值时左端点的最小值。

Sample Input

10
8 3 2 5 2 3 4 6 3 6

Sample Output

6 4

HINT

选出的子序列为5,2,3,4,6,3,只有唯一的最小值2和唯一的最大值6。

题解:首先我们用单调栈枚举每个数作为最大值的影响区间,然后枚举这个最大值。此时最小值怎么取呢?由于我们已经确定了最大值以及最大值的影响区间,那么最小值一定是取这个区间中的最小值,因为其他数的影响区间一定不会比最小值的影响区间大。区间最小值可以用RMQ处理。但是区间中可能有多个最小值,而影响区间包含当前最大值的只有一个,所以我们用vector维护每个数的所有出现位置,然后二分找到当前位置的前驱即后继,合法的最小值要么是前驱要么是后继。然后求一下最大值和最小值影响区间的交集即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=500010;
int n,m,top,ans,pos;
int v[maxn],mn[20][maxn],Log[maxn],lm[maxn],rm[maxn],ln[maxn],rn[maxn],st[maxn];
vector<int> p[maxn];
struct number
{
	int val,org;
}num[maxn];
bool cmp(const number &a,const number &b)
{
	return a.val<b.val;
}
inline int getmn(int a,int b)
{
	int k=Log[b-a+1];
	return min(mn[k][a],mn[k][b-(1<<k)+1]);
}
inline void updata(int a,int b)
{
	if(a>ans||(a==ans&&b<pos))	ans=a,pos=b;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i,j,a,b;
	for(i=1;i<=n;i++)	num[i].val=rd(),num[i].org=i;
	sort(num+1,num+n+1,cmp);
	for(i=1;i<=n;i++)
	{
		if(i==1||num[i].val>num[i-1].val)	m++;
		v[num[i].org]=m;
	}
	for(i=2;i<=n;i++)	Log[i]=Log[i>>1]+1;
	for(i=1;i<=n;i++)	p[v[i]].push_back(i),mn[0][i]=v[i];
	for(j=1;(1<<j)<=n;j++)	for(i=1;i+(1<<j)-1<=n;i++)	mn[j][i]=min(mn[j-1][i],mn[j-1][i+(1<<(j-1))]);
	for(st[top=0]=0,i=1;i<=n;i++)
	{
		while(top&&v[st[top]]<v[i])	top--;
		lm[i]=st[top]+1,st[++top]=i;
	}
	for(st[top=0]=0,i=1;i<=n;i++)
	{
		while(top&&v[st[top]]>v[i])	top--;
		ln[i]=st[top]+1,st[++top]=i;
	}
	for(st[top=0]=n+1,i=n;i>=1;i--)
	{
		while(top&&v[st[top]]<v[i])	top--;
		rm[i]=st[top]-1,st[++top]=i;
	}
	for(st[top=0]=n+1,i=n;i>=1;i--)
	{
		while(top&&v[st[top]]>v[i])	top--;
		rn[i]=st[top]-1,st[++top]=i;
	}
	for(i=1;i<=n;i++)
	{
		j=getmn(lm[i],rm[i]);
		b=lower_bound(p[j].begin(),p[j].end(),i)-p[j].begin(),a=b-1;
		if(a>=0&&rn[p[j][a]]>=i)	updata(min(rm[i],rn[p[j][a]])-max(lm[i],ln[p[j][a]])+1,max(lm[i],ln[p[j][a]]));
		if(b<(int)p[j].size()&&ln[p[j][b]]<=i)	updata(min(rm[i],rn[p[j][b]])-max(lm[i],ln[p[j][b]])+1,max(lm[i],ln[p[j][b]]));
	}
	printf("%d %d\n",ans,pos);
	return 0;
}
时间: 2024-10-05 01:27:18

【BZOJ4149】[AMPPZ2014]Global Warming 单调栈+RMQ+二分的相关文章

HUID 5558 Alice&#39;s Classified Message 后缀数组+单调栈+二分

http://acm.hdu.edu.cn/showproblem.php?pid=5558 对于每个后缀suffix(i),想要在前面i - 1个suffix中找到一个pos,使得LCP最大.这样做O(n^2) 考虑到对于每一个suffix(i),最长的LCP肯定在和他排名相近的地方取得. 按排名大小顺序枚举位置,按位置维护一个递增的单调栈,对于每一个进栈的元素,要算一算栈内元素和他的LCP最大是多少. 如果不需要输出最小的下标,最大的直接是LCP(suffix(st[top]),  suff

POJ2452---Sticks Problem(单调栈+RMQ,方法不够优秀)

Description Xuanxuan has n sticks of different length. One day, she puts all her sticks in a line, represented by S1, S2, S3, -Sn. After measuring the length of each stick Sk (1 <= k <= n), she finds that for some sticks Si and Sj (1<= i < j &

UVALive 6531 Go up the ultras 单调栈+RMQ

题目链接:点击打开链接 题意: 给定n座山 下面n个数字表示n座山的高度 若这座山u合法,则要满足: 1.若u的左边存在比u高的山,设v是u左边距离u最近的且严格比u高的山,在[v,u]之间至少有一座山x,使得x和u的高度差>=15000 2.右边也同理. 同时满足1.2的情况则算合法. 问: 输出所有合法的山. 思路: 求距离某个点最近的山就是维护一个单调栈,然后给山的高度求一个RMQ. 写写写... #pragma comment(linker, "/STACK:1024000000,

LA 6531 Go up the Ultras 单调栈+RMQ

题意:已经懒得吐槽了..有N个山峰,(N<=10^5),每个山峰有高度h,对应着每个山峰有一个d值,每个山峰到所有其他的严格比 它高的山峰都会经过一个最低值(山谷),d代表是h减去这些最低值中的最大值的差(如果不存在比它高的山峰那么d就是它本身的 高度),问有多少山峰的d>=150000米. 思路:利用单调栈维护每个峰左边第一个比它高的峰的位置l,右边第一个比它高的峰的位置r,对于r,我们从前向后维护一个单调减 序列,如果当前考虑的点i比栈顶的元素高度高,那么弹出栈顶元素,并将它的r置为i,直

hdu 5696 区间的价值 单调栈+rmq

区间的价值 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description 我们定义“区间的价值”为一段区间的最大值*最小值. 一个区间左端点在L,右端点在R,那么该区间的长度为(R−L+1). 现在聪明的杰西想要知道,对于长度为k的区间,最大价值的区间价值是多少. 当然,由于这个问题过于简单. 我们肯定得加强一下. 我们想要知道的是,对于长度为1∼n

POJ 2559 Largest Rectangle in a Histogram RMQ || 单调栈

题目链接:点击打开链接 题意就是求最大面积 枚举每个柱子作为起点 然后二分两边长度. 求个区间最值. #include<stdio.h> #include<iostream> #include<math.h> using namespace std; #define ll long long #define N 100100 inline bool rd(int &n){ int x = 0, tmp = 1; char c = getchar(); while

SPOJ MINSUB - Largest Submatrix(二分+单调栈)

http://www.spoj.com/problems/MINSUB/en/ 题意:给出一个n*m的矩阵M,和一个面积k,要使得M的子矩阵M'的最小元素最大并且面积大于等于k,问子矩阵M'的最小元素最大能是多少,并且求出最大的面积. 思路:二分一个最小元素x,转化为判断矩阵M里面是否存在一个子矩阵使得这个子矩阵的面积大于等于k并且所有元素都大于x. 用另一个矩阵,1表示该位置的元素大于等于x,0表示元素小于x. 转化为判断是否存在一个子矩阵元素为1的面积大于等于k. 这样可以用到早上学习的单调

spoj MINSUB 单调栈+二分

题目链接:点击传送 MINSUB - Largest Submatrix no tags You are given an matrix M (consisting of nonnegative integers) and an integer K.  For any submatrix of M' of M define min(M') to be the minimum value of all the entries of M'.  Now your task is simple:  fi

HDU 5089 Assignment(rmq+二分 或 单调队列)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 557    Accepted Submission(s): 280 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fr