[洛谷P1823]音乐会的等待 题解(单调栈)

[洛谷P1823]音乐会的等待

Description

N个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。
写一个程序计算出有多少对人可以互相看见。

输入格式:
输入的第一行包含一个整数N (1 ≤ N ≤ 500 000), 表示队伍中共有N个人。
接下来的N行中,每行包含一个整数,表示人的高度,以毫微米(等于10的-9次方米)为单位,每个人的调度都小于2^31毫微米。这些高度分别表示队伍中人的身高。

输出格式:
输出仅有一行,包含一个数S,表示队伍中共有S对人可以互相看见。

Solution

1.维护一个单调不增栈(因为只有两人间无个高于两人才可互相看见,中间间隔等高个人是可以的),当出现不符合单调性的元素时弹栈并更新答案ans;

2.对于每一个新入栈的元素:

(1)若低于当前栈顶元素,压栈;

(2)若等于栈顶元素,因为中间间隔等高的人是可见的,统计从当前元素开始前方有多少个等高的人,每有一个ans+1;

同时,在处理的过程中top--,假装弹栈,到找完所有等高的人后,若栈内不空,则栈顶和当前元素也能互相看到,ans++,此后再让top加上等高的个数,恢复原栈;

(3)若大于栈顶元素,弹栈至栈顶小于等于当前元素,每弹出一个元素,新元素和该元素都可以互相见到,ans++,到弹完所有不符合单调性的人后,若栈内不空,则栈顶和当前元素也能互相看到,ans++;

3.注意在弹栈和伪弹栈的过程中top>0,否则可能会RE,同时对操作后检验站内是否为空的操作只进行一次,防止重复计数;

Code

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int stack[500500],n,m,i,j,k,top=0,x,ans=0;

inline int rd(){
	int x=0;
	bool f=true;
	char c;
	c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=false;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	return f?x:-x;
} 

int main(){
	n=rd();
	for(i=1;i<=n;++i){
		x=rd();
		j=1;
		while(x>stack[top]&&top>0){
			--top;
			++ans;
		}
		while(x==stack[top]&&top>0){
			--top;
			++ans;
			++j;
		}
		if(top!=0) ++ans;
		top+=j;
		stack[top]=x;
	}
	printf("%lld
",ans);
} 

单调栈基础知识部分可以参考我的题解:http://www.cnblogs.com/COLIN-LIGHTNING/p/8474668.html

原文地址:https://www.cnblogs.com/COLIN-LIGHTNING/p/8486447.html