P1823

[COI2007] Patrik 音乐会的等待

题目描述

\(n\) 个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。

队列中任意两个人 \(a\)\(b\),如果他们是相邻或他们之间没有人比 \(a\)\(b\) 高,那么他们是可以互相看得见的。

写一个程序计算出有多少对人可以互相看见。

输入格式

输入的第一行包含一个整数 \(n\),表示队伍中共有 \(n\) 个人。

接下来的 \(n\) 行中,每行包含一个整数,表示人的高度,以毫微米(等于 \(10^{-9}\) 米)为单位,这些高度分别表示队伍中人的身高。

输出格式

输出仅有一行,包含一个数 \(s\),表示队伍中共有 \(s\) 对人可以互相看见。

样例 #1

样例输入 #1

7 
2 
4 
1 
2 
2 
5 
1

样例输出 #1

10

提示

数据规模与约定

对于全部的测试点,保证 \(1\le\) 每个人的高度 \(< 2^{31}\)\(1 \le n \le 5\times 10^5\)

由于这道题要考虑身高相同的情况所以不能像普通单调栈那样存最近的大于它的点
维护一个单调递减的单调栈
对于每个i 在它之前查找栈中比它大的第一个元素的位置即可
点击查看代码
#include<bits/stdc++.h>
#define il inline
#define rg register
#define ldb double
#define lst long long
#define rgt register int
#define N 500050
using namespace std;
const int Inf=1e9;
il int read()
{
	int s=0,m=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}
	while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return m?-s:s;
}

int n,top;lst Ans;
int H[N],stk[N];

il void Calc(rgt x)
{
	rgt le=0,ri=top,mid,ret=0;
	while(le<=ri)
	{
		mid=(le+ri)>>1;
		if(H[stk[mid]]>x)ret=mid,le=mid+1;
		else ri=mid-1;
	}
	if(!ret)Ans+=top;
	else Ans+=top-ret+1;
}
int main()
{
	n=read();
	for(rgt i=1;i<=n;++i)H[i]=read();
	for(rgt i=1;i<=n;++i)
	{
		Calc(H[i]);
		while(top>0&&H[i]>H[stk[top]])--top;
		stk[++top]=i;
	}return printf("%lld\n",Ans),0;
}
posted @ 2023-01-16 16:47  PKU_IMCOMING  阅读(16)  评论(0)    收藏  举报