jzoj栈【ST表】【模拟】

>Description
在这里插入图片描述


>Input
在这里插入图片描述

>Output
在这里插入图片描述


>Sample Input
5
1 4 3 5 2

>Sample Output
1 2 4 3 5

在这里插入图片描述


>解题思路
用三个指针 l、r、keyl 指向a数组,位置l~ r表示是已经入了栈的,keyl~n是等待入栈的数。
a数组不用进行预先处理,l为栈底,r为栈顶。每次要存入一个数到b数组(答案里),就找到keyl~n中最小的数,如果l<=r的话,再与 al 和ar进行比较取最小的值(因为栈底和栈顶的数都可以直接弹出),把最小的值记录到b数组里,还要标记此数已被取,同时把 r 和 keyl 更新,如果最小的数在keyl~n中的话(位置为s吧),就把 r 更新为s-1,keyl为s+1。接着继续循环。

但是每次都要枚举找keyl~n中最小的数的话会超时,所以这里要植入ST表。


>代码

#include<iostream>
#include<cstdio>
using namespace std;
int n,c,l,r,keyl,a[100005],b[100005],stu[100005][20],st[100005][20],ll[100005];
bool yd[100005];
int main()
{
//	freopen("stack.in","r",stdin);
//	freopen("stack.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	 scanf("%d",&a[i]);
	for(int k=0;k<=20;k++)
	 for(int i=1;i+(1<<k)-1<=n;i++)
	  if(k==0) stu[i][k]=a[i],st[i][k]=i;
	  else
	  {
	  	int x=stu[i][k-1],y=stu[i+(1<<(k-1))][k-1];
	  	if(x<y) stu[i][k]=x,st[i][k]=st[i][k-1];
	  	else stu[i][k]=y,st[i][k]=st[i+(1<<(k-1))][k-1];
	  } //ST表,stu记录最小值,st记录最小值的位置
	ll[0]=-1;
	for(int i=1;i<=n;i++)
	 ll[i]=ll[i>>1]+1; //这个在使用ST表的时候要用到
	l=keyl=1;
	for(int i=1;i<=n;i++)
	{
		int p=100000,pp=0;
		if(keyl<=n)
		{
			int x=stu[keyl][ll[n-keyl+1]],y=stu[n-(1<<ll[n-keyl+1])+1][ll[n-keyl+1]];
		    if(x<y) p=x,pp=st[keyl][ll[n-keyl+1]];
		    else p=y,pp=st[n-(1<<ll[n-keyl+1])+1][ll[n-keyl+1]];
		}
		if(l<=r)
		{
			if(a[l]<p) p=a[l],pp=l;
			if(a[r]<p) p=a[r],pp=r;
		} //上文有详细解释
		b[i]=p; yd[pp]=1;
		r=max(r,pp-1); keyl=max(keyl,pp+1); //更新(注意要max一下)
		while(yd[l]) l++;
		while(yd[r]) r--; //不计算已经记录过的数
	}
	for(int i=1;i<=n;i++)
	 printf("%d ",b[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值