P1823 Patrik 音乐会的等待
题目描述
N个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟进行谈笑风生。队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。
写一个程序计算出有多少对人可以互相看见。
输入输出格式
输入格式:
输入的第一行包含一个整数N (1 ≤ N ≤ 500 000), 表示队伍中共有N个人。
接下来的N行中,每行包含一个整数,表示人的高度,以毫微米(等于10的-9次方米)为单位,每个人的调度都小于2^31毫微米。这些高度分别表示队伍中人的身高。
输出格式:
输出仅有一行,包含一个数S,表示队伍中共有S对人可以互相看见。
数据范围 \(n<=500,000\) 限定le我们必须要使用\(o(N)\)算法
那我们来简单的分析一下。
对于在一个高人之前的,naive的人,对于这个高人之后的人,就没有什么影响le
这就启示我们需要一个在线性时间内维护单调性的数据结构不就是单调栈么? 说的这么麻烦
我们维护一个从栈顶到栈底单调递增的单调栈
在一个元素进栈的时候,他有可能弹出去几个比他naive的人,他就可以和这些人交流人生经验,如果维护好单调性后,没有入栈前,栈非空,就可以和栈顶的兄die一起van游戏
就是这样了。
然后有可能有重复身高的人,要处理一下
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int manx=501000;
struct node
{
int num;//相同身高的人的个数
int hig;//高度
bool operator <= (const node &a)const
{
return hig <= a.hig;
}
bool operator == (const node &a)const
{
return hig==a.hig;
}
void operator += (const node &a)
{
num+=a.num;
return ;
}
};
node stack[manx];
int top;
int ans=0;
void push(int n)
{
node pas;
pas.hig=n;pas.num=1;
while(stack[top]<=pas&&top)
{
ans+=stack[top].num;//谈笑风生
if(stack[top]==pas)//相同身高的人
pas+=stack[top];//合并
top-=1;
}
if(top) ans+=1;//和栈顶的兄die交流
stack[++top]=pas;
}
int main()
{
int n;
scanf("%d",&n);
int a;
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
push(a);//入栈
}
printf("%d",ans);//答案
}