来源
-
yxc大佬已经讲得很好了,这里只是把图按照自己理解画得形象一点,顺便归纳一下
性质
-
连续的相同排序操作,只需取
最长的那一次
进行依次排序即可,不用每次都排序。-
连续的 0 qi 操作,使[a1 , aqi]元素为降序。
- 对于其中的任何一次操作j,如果之前的所有操作的区间都比当前的要短(aqi<=aqj),则之前所有排序效果可以等效为当前排序中[a1 , aqi]部分,[aqi,aqj]保持原序不变;
- 对于其中的任何一次操作j,如果之后的所有操作的区间都比当前的要短(aqi>=aqj),则之后所有排序效果可以等效为当前排序中[a1 , aqi]部分,[aqi,aqj]保持原降序不变;
-
连续的 0 qi 操作,使[a1 , aqi]元素为升序。
同理可得相似结论。
-
-
两种排序操作交替,并且相邻两个排序的范围的重合区间长度越来越短,则每次只需
交换重合的区间
。将研究对象看作
重合区间
,可以发现重合区间
的端点不断地向中间靠拢,并且每一次排序重合区间
中的元素都要前后翻转一遍 -
两种排序操作交替,并且相邻两个排序的范围的重合区间长度越来越长,则只需对
最后一次操作
排序,并且删除前面两次交替的排序。
符号说明
- 蓝线:相邻两个排序范围的重合区间范围
- 箭头:每次排序的区间
图示
建议结合视频一起看
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 100010;
int n, m;//序列长度,操作次数
PII stk[N];//栈,存储每次操作的操作类型q和参数p
int ans[N];//答案
int main()
{
scanf("%d%d", &n, &m);
int top = 0;
while (m -- )
{
int p, q;//操作类型和参数
scanf("%d%d", &p, &q);
if (!p)//操作1:a1~aq降序
{
while (top && stk[top].x == 0)
q = max(q, stk[top -- ].y);//出现连续的操作1,我们取q最大(区间最长,性质1.1)
while (top >= 2 && stk[top - 1].y <= q)
//如果当前的操作1比上一次的操作1范围大,则删除之前的两次排序交替的操作(仅保留最长区间,性质3)
top -= 2;
stk[ ++ top] = {0, q};//存本次最佳操作
}
else if (top)//操作2:aq~an升序
//&&且操作1已经进行过(操作二第一个用没效果:初始序列是升序的,根据性质1.2,无需再进行一次排序)
{
while (top && stk[top].x == 1) q = min(q, stk[top -- ].y);//出现连续的操作2,我们取q最小(区间最长,性质1.2)
while (top >= 2 && stk[top - 1].y >= q) top -= 2;//如果当前的操作2比上一次的操作2范围大,则删除之前的两次排序交替的操作(仅保留最长区间,性质3)
stk[ ++ top] = {1, q};
}
}
//在结果数组里面填数字
//枚举每一次操作
int k = n, l = 1, r = n;
for (int i = 1; i <= top; i ++ )
{
if (stk[i].x == 0)//操作1:a1~aq降序
//右区间左移
while (r > stk[i].y && l <= r) ans[r -- ] = k -- ;//移动r值 ,并赋值
else//操作2:aq~an升序
//左区间右移
while (l < stk[i].y && l <= r) ans[l ++ ] = k -- ;
if (l > r) break;//填完了
}
//若l < r, 表示中间还有些数没有填上(由于有优化,并且询问的次数不一定和元素个数一样)
//这个地方不太好理解,建议看图,这里的操作次数top每增加1,排序方式就要改变一次
if (top % 2)//操作次数为奇数,则下一次操作为前缀操作,降序填充剩余区间的数
while (l <= r) ans[l ++ ] = k -- ;
else//操作次数为偶数,则下一次操作为后缀操作,升序填充剩余区间的数
while (l <= r) ans[r -- ] = k -- ;
for (int i = 1; i <= n; i ++ )
printf("%d ", ans[i]);
return 0;
}