疯狂的企鹅 CSU - 2147 (队列+双向链表维护)

在鹅厂工作的DJ开始训练起了鹅厂的企鹅们,现在DJ教小企鹅玩一个疯狂的游戏(危险游戏,小朋友请勿模仿)。

现在有一排小企鹅,从左到右编号为1....N,每个小企鹅有一个数字,每天早上,如果一个小企鹅发现他右边的小企鹅的数字比他的小,他就会消灭这个小企鹅。问到了第几天才会没有小企鹅可以被消灭,你需要输出天数-1的值

注:所有小企鹅的数字是1...N的排列

Input

每组数据输入格式如下:

第一行一个整数N (N<=10^6)

第二行N个整数,表示1...N号小企鹅的数字

Output

每组数据一行,每行一个整数表示输出天数-1的值

Sample Input

4
4 2 1 3

Sample Output

2

Hint

对于第一组数据:

DAY1:6 2 3 4 5

DAY2:6 3 4 5

DAY3:6 4 5

DAY4:6 5

DAY5:6

对于第二组数据:

DAY1:6 3 5

DAY2:6 5

DAY3:6

对于第三组数据:

DAY1:6

这么个题目卡了我快二十天。。。。

本题的思路就是仅对被删除元素进行维护,以便最终达到O(n)的复杂度模拟。

上代码吧,都写在注释里了。

#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
const int size=1e6+5;
int arr[size],last[size],nxt[size];
int del[size];
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=n;i++) 
		{
			scanf("%d",&arr[i]);
			nxt[i]=i+1;
			last[i]=i-1;
		}
		last[0]=n;
		nxt[n]=0;
		nxt[0]=1;
		del[0]=1;
		//构建双向链表 
		queue<int> q,p;
		for(int i=2;i<=n;i++)
		{
			if(arr[i]<arr[i-1])
			{
				del[i]=1;//将所有第一轮就会被删除的东西打上标记并入队 
				q.push(i);
			}
		}
		int ans=0;
		while(!q.empty())
		{
			ans++;
			while(!q.empty())
			{
				int x=q.front();
				q.pop();
				if(last[x]&&nxt[x]&&del[last[x]]!=1&&del[nxt[x]]!=1&&arr[nxt[x]]<arr[last[x]])
				{
					p.push(nxt[x]);//被删除的元素全部入队 
					del[nxt[x]]=1;//所有被删除的打上标记 
				}
				nxt[last[x]]=nxt[x];
				last[nxt[x]]=last[x];
				//不论如何都将被删除的元素的前后元素连接起来 
			}
			q=p;
			while(!p.empty()) p.pop();
		}
		cout<<ans<<endl;
	}
} 

猜你喜欢

转载自blog.csdn.net/baiyifeifei/article/details/81710384