疯狂的企鹅 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;
}
}