第十二届蓝桥杯B组省赛题目,双向排列

传送门嗖啪
题目大意
(自己看题吧)
思路
可以画出来,连续的同一个方向的操作可以合并在一起,只取最大的那一个,
但是还有后面的比前边的大的可能,这时候就会发现,如果后面一个比前面的范围大的话,就要去掉中间的操作,包括去掉那个范围小的,详细的解说放在了下面代码中,大家自行观看,上代码!

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
#include <string>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define sc(a) scanf("%lld",&a)
#define pf(a) printf("%d",a) 
#define endl "\n"
#define int long long
#define x first
#define y second

#define pii pair<int, int>

const int N = 100010;

int n, m, p, q;

pii stk[N];//这是个栈,用来存储我们所有的操作 
/*
第一个关键字表示是什么操作,是前缀还是后缀
 第二个关键字是存下标是什么
*/ 
int ans[N];//存一下答案 

signed main()
{
	sc(n);sc(m);
	int top = 0;//栈顶元素 
	for(int i=1;i<=m;i++)
	{
		sc(p);sc(q);
		if(!p)//p是0,表示是前缀操作 
		{
			//对于连续的前缀操作,只保留一个最大的 
			//栈是不空的,栈顶元素是前缀操作的话 ,保留一个最大的 
			while(top && stk[top].x==0) q=max(q, stk[top--].y);
			/*
			如果前缀和是不连续的话, 要删掉前面所有长度比当前小的前缀操作
			 
			*/
			while (top >= 2 && stk[top - 1].y <= q) top -= 2;
            stk[ ++ top] = {0, q};
		}
		else if (top)//第一个操作不能是后退操作,第一个操作是后退操作没有意义 
        {
        	//判断一下栈非空 ,并且栈顶的操作跟我们现在的操作一致
			//这里top不能去掉,因为后面的min函数中有top-- 
            while (top && stk[top].x == 1) q = min(q, stk[top -- ].y);
            /*这里一定是同类操作比较y,因为上一步top--,所有这里top
			指向了stk[top].x=0的栈顶*/ 
			while (top >= 2 && stk[top - 1].y >= q) top -= 2;
            stk[ ++ top] = {1, q};
        }
	}
	/*
	倒着填所有的数,本题就相当于最边上的数不变,然后
	边上不变的数的个数依次增多 
	*/
	int k = n, l = 1, r = n;
    for (int i = 1; i <= top; i ++ )
    {
        if (stk[i].x == 0)
            while (r > stk[i].y && l <= r) ans[r -- ] = k -- ;
        else
            while (l < stk[i].y && l <= r) ans[l ++ ] = k -- ;
        if (l > r) break;
    }
    //这时可能所有的并没有完全排序 
    /*
	如果top是奇数,说明刚刚完成了一次左边, 
	没有被排到的也就在左边被排序,也就是逆序,l++
	从大到小,从左开始排 
	*/ 
	if (top % 2)
        while (l <= r) ans[l ++ ] = k -- ;
    else
        while (l <= r) ans[r -- ] = k -- ;
	/*
	偶数说明刚刚完成右操作,顺序,也就是从右到左得逆序,r--
	*/ 
    for (int i = 1; i <= n; i ++ )
        printf("%d ", ans[i]);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值