Two-way sorting of the 12th Lanqiao Cup Provincial Competition

source

  1. acwing analysis video

    Mr. yxc has already said it very well, here I just draw the picture according to my own understanding, and summarize it by the way

  2. the code

nature

  1. For consecutive identical sorting operations, you only need to 最长的那一次sort them sequentially, instead of sorting each time.

    1. Continuous 0 q i operations make [a 1 , a qi ] elements in descending order.

      1. For any one of the operations j, if the range of all previous operations is shorter than the current one (a qi <= a qj ), then all previous sorting effects can be equivalent to the [a 1 , a qi ] part of the current sorting , [a qi ,a qj ] keep the original order unchanged;
      2. For any one of the operations j, if the range of all subsequent operations is shorter than the current one (a qi >=a qj ), then all subsequent sorting effects can be equivalent to the [a 1 , a qi ] part of the current sorting , [a qi ,a qj ] keep the original descending order unchanged;
    2. Continuous 0 q i operations make [a 1 , a qi ] elements in ascending order.

      Similarly, similar conclusions can be drawn.

  2. The two sorting operations are alternated, and the length of the overlapping range of the two adjacent sorting ranges is getting shorter and shorter, and only one time is required 交换重合的区间.

    Think of the research object as 重合区间that the endpoints that can be found 重合区间are constantly moving closer to the middle, and 重合区间the elements in each sorting have to be flipped back and forth

  3. Two kinds of sorting operations are alternated, and the overlapping interval length of two adjacent sorting ranges is getting longer and longer, then only need to sort 最后一次操作and delete the previous two alternate sortings.

Symbol Description

  1. Blue line: the overlapping interval range of two adjacent sorting ranges
  2. Arrows: intervals for each sort

icon

It is recommended to watch it together with the video

insert image description here

the code

#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;
}

Guess you like

Origin blog.csdn.net/qq_33843237/article/details/129694608