诺诺的队列
题目描述
诺诺表现、成绩双优,于是校长给她一笔money,让她去外地玩玩。由于本地没有飞机场,所以诺诺只能坐火车去咯。所以诺诺今天去火车站买票,却看到了N多人在火车站里啊,诺诺一阵头晕。机灵的她突然发现,有N个人在队伍里(和上文的N毫无关系- -||),人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。
诺诺想计算出有多少对人可以互相看见,那么你能帮帮诺诺吗?
本题数据范围:
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循环的,不过我是以一个人为单位能看到哪些人为计算,没有一次性算完,对于我这种初学者会简单一点。