CF 320D Psychos in a Line 链表维护(递增序列)

题意:给出长度为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次.

无论什么时候,队列中某个元素往下走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;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值