诺诺的队列

诺诺的队列

题目描述

    诺诺表现、成绩双优,于是校长给她一笔money,让她去外地玩玩。由于本地没有飞机场,所以诺诺只能坐火车去咯。所以诺诺今天去火车站买票,却看到了N多人在火车站里啊,诺诺一阵头晕。机灵的她突然发现,有N个人在队伍里(和上文的N毫无关系- -||),人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。队列中任意两个人AB,如果他们是相邻或他们之间没有人比AB高,那么他们是可以互相看得见的。
诺诺想计算出有多少对人可以互相看见,那么你能帮帮诺诺吗?

本题数据范围:
    40%
的测试数据:N≤10000
    80%
的测试数据:N≤100000
    100%
的测试数据:N≤500000

输入格式 2116.in

    输入的第一行包含一个整数N (1≤N≤500 000), 表示队伍中共有N个人;
    接下来的N行中,每行包含一个整数,表示人的高度,人的高度<1000000

输出格式 2116.out

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

输入样例 2116.in

7
2
4
1
2
2
5
1

输出样例 2116.out

10

问题分析:

    这道题也可以用单调递减队列解决。但是由于身高有可能相同,所以该题不是严格的单调队列,对于相等的数,我们只统计而不删除队尾,否则会得到错误的答案。例如样例中a[4]=a[5]=2,由于a[4]并没有挡住a[5]视线,所以在a[5]入栈前a[4]被出栈了,可是对于a[6],他可以看见a[4],所以( 4,6)这一对就没有被统计进去,所以a[4]删不得。

    通过分析样例会知道,当前的人能看到前面的,只有前面第一个比它高的人,以及前面比它矮的人。

    利用单调队列,进来一个人,前面比它矮的人就是它能看到的,然后就可以把前面矮的人删掉了,因为前面比它矮的人,同样是看不见它后面的人的(都被它挡住了)。

    这样一来,用单调不上升序列,即可算出。至于为什么是不上升,因为在相等的情况下,同样是可以保留下来的,因为后面比它高的同样能看到这些一样高的,前者不会被后者身高一样,而挡住后面的。

#include
#include
using namespace std;
const int maxn=500005;
long long n,a[maxn],q[maxn],ans;
int main()
{
	freopen("2116.in","r",stdin);
	freopen("2116.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	long long head=1,tail=0;
	for(int i=1;i<=n;i++)
	{
		while(head<=tail&&a[q[tail]]=1;i--)
	{
		while(head<=tail&&a[q[tail]]
    PS:这是一份特别迷的代码,其实是可以去掉一次for循环的,不过我是以一个人为单位能看到哪些人为计算,没有一次性算完,对于我这种初学者会简单一点。


你可能感兴趣的:(单调队列)