音乐会的等待(数据结构篇之单调栈)

题目描述

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

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

输入输出格式

输入格式:

输入的第一行包含一个整数N (1 ≤ N ≤ 500 000), 表示队伍中共有N个人。

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

输出格式:

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

输入输出样例

输入样例#1:
7 
2 
4 
1 
2 
2 
5 
1
输出样例#1:
10

思路:

这道题可以使用单调栈解决。

首先,我们整理一下思路,对于队伍中的一个人来说,他可能看到自己前面的人,也可能看到自己后面的人,但是如果把前后两种情况都考虑的话,寻找一遍下来一定有很多重复,所以我们决定只考虑每个人的前或后一侧的情况,这里我们对每个人的前面的人讨论

如果一个人身后存在一个比他高的人,那么他将不会再被看见,因此,可以可根据身高维护一个单调栈,从左向右依次扫描,扫描到 A 时,我们希望栈里保存的是 A 之前,能够和 A 相互看到的人。具体实现时,栈中的元素是自下而上递减的,这就要求我们再加元素时保证栈顶元素大于等于加进的那个元素,可以用二分法求出栈中第一个大于等于输入的元素的值,并把这个元素以上的元素全部弹出,把输入的元素放进栈中。

写代码时一定要注意:

1.第一个元素单独输入,道理很显然

2.由于第一个元素是单独输入的,所以栈中是有一个元素的,初始时把top设为1

3.根据题意,身高相同的人并不会互相遮挡

#include<iostream>
using namespace std;
int st[500010],n,top=1,ans,m;
int main()
{
    cin>>n;
    int a;
    cin>>st[1];
    for(int i=2;i<=n;i++)
    {
        cin>>a;
        if(st[top]>a)
        {
            top++,ans++,st[top]=a;
        }
        else
        {
            int l=1,r=top;
            while(l<r)
            {
                m=(l+r)>>1;
                if(r==l+1)m=r;
                if(a>=st[m])r=m-1;
                else l=m;
            }
            ans+=top-l+1;
            while(top>0&&st[top]<a)top--;
            st[++top]=a;
        }
    }
    cout<<ans;
}
原文地址:https://www.cnblogs.com/thmyl/p/6065610.html