【洛谷】P8747 [蓝桥杯 2021 省 B] 双向排序 的题解

【洛谷】P8747 [蓝桥杯 2021 省 B] 双向排序 的题解

传送门

思路

这道题的意思就是有 n n n 个数,是从 1 1 1 n n n,和 m m m 次操作,每次操作输入一个 p p p q q q p p p 0 0 0 的时候把 1 1 1 q q q 降序排, p p p 1 1 1 的时候把 q q q n n n 升序排。

根据数据范围你会发现, n n n m m m 最大可以达到 1 0 5 10^5 105,如果每次操作我们都排序一下的话,时间复杂度是 O ( m n l o g n ) O(mnlogn) O(mnlogn),会达到 1 0 11 10^{11} 1011 以上,这样做肯定是不行的。

其实我们会发现,每次排序都会浪费掉很多时间来处理一些不必要的东西,或者说有很多操作是重复的。所以,我们先将 [ 1 , x ] [1,x] [1,x] 降序排,再将 [ 1 , y ] [1,y] [1,y] 降序排,其实我们可以直接把 [ 1 , x ] [1,x] [1,x] 降序排这个操作去掉,这是因为 [ 1 , x ] [1,x] [1,x] 只是 [ 1 , y ] [1,y] [1,y] 的一部分。从 [ x , n ] [x,n] [x,n] 升序排也是一样的道理,我们先将 [ x , n ] [x,n] [x,n] 升序排,再将 [ y , n ] [y,n] [y,n] 升序排,其实我们可以直接把 [ x , n ] [x,n] [x,n] 升序排这个操作去掉。

这样子我们可以发现每次降序排和升序排我们只取范围最大的那个,范围比它小或者等于它的操作其实都是不必要的,我们可以统统去掉。因此呢,我们最后真正需要的操作是升序排降序排依次交替的。我们可以发现,如果第一次操作是 [ x , n ] [x,n] [x,n] 升序排,那么我们也可以忽略掉,因为刚开始的时候我们的数据本来就是升序的,我们把部分升序排之后也是不会引起任何变化的。所以第一次操作必定是 [ 0 , x ] [0,x] [0,x] 降序排。

这样的话我们就可以找规律啦,例如:1 2 3 4 5 6 7 8 9

  1. 第一次我们将 [ 1 , 3 ] [1,3] [1,3] 降序排,变成:3 2 1 4 5 6 7 8 9

  2. 第二次我们将 [ 7 , 9 ] [7,9] [7,9] 升序排,还是:3 2 1 4 5 6 7 8 9

  3. 第三次我们将 [ 1 , 6 ] [1,6] [1,6] 降序排,变成:6 5 4 3 2 1 7 8 9

  4. 第四次我们将 [ 4 , 9 ] [4,9] [4,9] 升序排,变成:6 5 4 1 2 3 7 8 9

  5. 第五次我们将 [ 1 , 5 ] [1,5] [1,5] 降序排,变成:6 5 4 2 1 3 7 8 9

相信你们发现了一个规律,就是排序的时候,我们会有一些数字被固定,这里我来证明一下。刚开始我们在 [ 1 , n ] [1,n] [1,n] 的时候,我们将 [ 1 , x ] [1,x] [1,x] 降序排列,由于最初我们的数据都是升序的,所以 ∀ b ∈ [ x + 1 , n ] > ∀ a ∈ [ 0 , x ] \forall b \in [x+1,n]> \forall a\in[0,x] b[x+1,n]>a[0,x]。那么之后我们对 [ y , n ] [y,n] [y,n] 升序排列的话其实 [ x , n ] [x,n] [x,n] 这部分是不变的,注意看上面的 3 3 3 4 4 4,这是因为 [ y , x ] ∈ [ 0 , x ] < [ x + 1 , n ] [y,x]\in[0,x]<[x+1,n] [y,x][0,x]<[x+1,n],所以 [ x + 1 , n ] [x+1,n] [x+1,n] 这部分的任意值是始终大于 [ y , x ] [y,x] [y,x] 中的任意值。因此我们对 [ y , n ] [y,n] [y,n] 升序排序的话,其实 [ x , n ] [x,n] [x,n] 这部分不会挪动位置。换句话说, [ x , n ] [x,n] [x,n] 已经被固定下来了。

我们观察一下上面的 1 1 1 2 2 2,它们没有任何交集,所以不会固定任何点,不过到了 3 3 3 4 4 4 的时候,他们就有交集了。并且发现, 1 1 1 2 2 2 这两次操作其实也是没有必要的,这是因为 [ 1 , 6 ] [1,6] [1,6] 中的 6 6 6 是大于 [ 1 , 3 ] [1,3] [1,3] 中的 3 3 3 的,还是上面的道理,这是因为 [ 1 , x ] [1,x] [1,x] 只是 [ 1 , y ] [1,y] [1,y] 的一部分。

那么还有一个地方,就是为啥接下来的 [ z , n ] [z,n] [z,n] 升序排也可以去掉? 我们可以这样想,后半段本身里面有一部分是升序排的,如果我们 z z z 在升序排那一部分后面,那这个操作本身就没有意义,比如:3 2 1 4 5 6 7 8 9 [ 3 , 9 ] [3,9] [3,9] 本身已经升序了,我们让 [ 4 , 9 ] [4,9] [4,9] 再升序排,也没有意义。那如果我们在3的前面升序排,比如 [ 2 , 9 ] [2,9] [2,9],就会变成 3 1 2 4 5 6 7 8 9,之后我们对一个大于等于 3 3 3 的降序排,例如 [ 1 , 6 ] [1,6] [1,6] 就会变成 6 5 4 3 2 1 7 8 9,你会发现我们直接对 3 1 2 4 5 6 7 8 9 [ 1 , 6 ] [1,6] [1,6] 降序排结果也是这样。

代码

#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
int n, m, ans[100005];
PII stk[100005];
int main() {
	//freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	cin >> n >> m;
    int top = 0;
    while(m --) {
        int p, q;
        cin >> p >> q;
        if (!p) {
            while(top && stk[top].first == 0) q = max(q, stk[top --].second);
            while(top >= 2 && stk[top - 1].second <= q) top -= 2;
            stk[++ top] = {0, q};
        }
        else if (top) {
            while (top && stk[top].first == 1) q = min(q, stk[top -- ].second);
            while (top >= 2 && stk[top - 1].second >= q) top -= 2;
            stk[++ top] = {1, q};
        }
    }
    int k = n, l = 1, r = n;
    for (int i = 1; i <= top; i ++) {
        if (stk[i].first == 0) 
            while (r > stk[i].second && l <= r) ans[r --] = k --;
        else 
            while (l < stk[i].second && l <= r) ans[l ++] = k --;
        if (l > r) break;
    }
    if (top % 2) 
        while (l <= r) ans[l ++] = k --;
    else 
        while (l <= r) ans[r --] = k --;
    for (int i = 1; i <= n; i ++)
        cout << ans[i] << " ";
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值