lanqiao 1458 双向排序(栈优化)

This commit is contained in:
2025-04-07 17:01:18 +08:00
parent 5090cc5e79
commit 8b0ec58d27

52
12lanqiao/test9-2.cpp Normal file
View File

@@ -0,0 +1,52 @@
// lanqiao 1458 双向排序(栈优化)
#include<bits/stdc++.h>
using namespace std;
/*
题意:
该题目首先给定了一个升序序列,通过两种操作(前缀降序和后缀升序)对序列进行处理最后得到一个结果序列
通过分析题目可以得到以下性质:
1.连续的前缀操作和后缀操作,只需要暴力最长区间对应操作即可,其余操作均属于无效操作
2.对于左右交替的有效操作可以使用线段树或者Splay树处理交集区间的翻转
由于在左右交替的过程中,交集区间不断缩小,所以也可以从开到和结尾处朝着中间填数
*/
const int N = 1e5 + 10;
pair<int, int> stk[N]; // 栈记录有效操作
int s[N], top; // 记录栈顶
int main(){
int n, m; cin >> n >> m;
while(m--){
int p, q; cin >> p >> q;
if(p == 0){ // 前缀降序
// 处理连续的前缀降序操作, 保留最长区间的有效操作
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 l = 1, r = n, k = n;
for(int i = 1; i <= top; i++){
if(stk[i].first){
while(l < stk[i].second && l < r) s[l++] = k--; // 升序从左侧开始填充
}else{
while(r > stk[i].second && l < r) s[r--] = k--; // 降序从右侧开始填充
}
}
// 最后补充未填充的数字
if(top % 2){
while(l <= r) s[l++] = k--;
}else{
while(l <= r) s[r--] = k--;
}
for(int i = 1; i <= n; i++) cout << s[i] << " ";
return 0;
}
/* test samples 3 1 2
3 3
0 3
1 2
0 2
*/