双向排序 - 蓝桥云课 (lanqiao.cn)
题目描述
题目分析
六十分解法如下:按照题意简单排序
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, p, q, a[N];
bool cmp(int x, int y)
{
return x > y;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++)a[i] = i;
for(int i = 1; i <= m; i ++)
{
cin >> p >> q;
if(p == 0)sort(a + 1, a + 1 + q, cmp);
else sort(a + q, a + 1 + n);
}
for(int i = 1; i <= n; i ++)cout << a[i] << ' ';
return 0;
}
满分解法:
对于每一次操作我们在每次连续的升序和降序操作中只需要选呢个范围最大的即可,范围小的操作对于范围大的操作相当于重复没用的操作,因此我们正真需要的操作是升序降序依次交替出现的,第一个有效操作一定为p = 0,因为刚开始一定是升序的,再进行升序操作是无效操作
在排序中会不断有数字被固定
由于升降交替排序,先将[1, x]降序排序,再将[y, n]升序排序,这里y <= x,我们可以发现[x, n]这段会被固定而不发生变化
同理,先将[x, n]升序排序,再将[1, y]降序排序,这里y <= x,我们可以发现[1, y]这段会被固定而不发生变化
使用ans不断记录被固定的数,最后没固定的再看其操作,
由于第一个有效操作一定是p = 0,故如果剩余的操作次数为奇数相当于降序操作确定了[x, n]的位置,如果为偶数个操作次数就相当于后缀做升序,就意味着确定前缀[1, y]的位置
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
pair<int, int> stk[N];
int n, m, top, p, q, ans[N];
int main()
{
cin >> n >> m;
while(m --)
{
cin >> p >> q;
if(p == 0)
{
while(top && stk[top].first == 0)
{
q = max(q, stk[top --].second);
}
//123456
//321456
//432156
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 left = 1, right = n, k = n;
for(int i = 1; i <= top; i ++)
{
if(stk[i].first == 0)
{
while(right > stk[i].second && left <= right)//确定[x, n]
{
ans[right --] = k --;
}
}
else
{
while(left < stk[i].second && left <= right)//确定[1, y]
{
ans[left ++] = k --;
}
}
if(left > right)break;
}
if(top % 2)
{
while(left <= right)ans[left ++] = k --;
}
else
{
while(left <= right)ans[right --] = k --;
}
for(int i = 1; i <= n; i ++)
{
cout << ans[i] << ' ';
}
return 0;
}