题意:给出长度为n的排列a, 每一轮同时删除若干个数,若a[i]<a[i-1],则删除a[i].若无操作 则游戏结束.
n,a[i]<=1e5.问经过多少轮游戏结束?
最后的序列为非递减的,否则还能继续操作.
每次删除的是一段连续的递减子序列(开头不删).
当a[i]>a[i+1]时则删除a[i+1] 用链表来记录当前元素的下一个元素位置.
也就是当a[i]>a[nxt[i]]时 删除a[nxt[i]] 然后令i=nxt[i]继续往下删除.
然后用队列来维护当前可能开始删除的头节点即可.
最坏情况下,删除一个点然后加入一个结点入队列,所以总的队列元素(遍历队列次数)不会超过n次.
n,a[i]<=1e5.问经过多少轮游戏结束?
最后的序列为非递减的,否则还能继续操作.
每次删除的是一段连续的递减子序列(开头不删).
当a[i]>a[i+1]时则删除a[i+1] 用链表来记录当前元素的下一个元素位置.
也就是当a[i]>a[nxt[i]]时 删除a[nxt[i]] 然后令i=nxt[i]继续往下删除.
然后用队列来维护当前可能开始删除的头节点即可.
最坏情况下,删除一个点然后加入一个结点入队列,所以总的队列元素(遍历队列次数)不会超过n次.
无论什么时候,队列中某个元素往下走k次 则删除k个结点.所以队列元素总的往下走次数(i=nxt[i])不会超过n次 所以综上时间复杂度为O(n).
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
int n,a[N],nxt[N],last[N],q[N];
int main()
{
int top=0,ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),nxt[i]=i+1,last[i]=i-1,q[top++]=i;
nxt[0]=1,last[n+1]=n;
bool flag=true;
while(flag)
{
flag=false;
int s=0,now=0;
while(now<top)
{
int p=q[now],i=p,cnt=0;
while(nxt[i]<=n)
{
if(a[i]>a[nxt[i]])
flag=true,i=nxt[i],cnt++;
else
break;
}
if(cnt)
{
nxt[p]=nxt[i];
last[nxt[i]]=p;
q[s++]=p;//
}
while(q[now]<nxt[i]&&now<top)
now++;
}
top=s;
//printf("%d ",s);
if(flag)
ans++;
}
printf("%d\n",ans);
return 0;
}