双向排序(Java)

双向排序

双向排序(Java)_第1张图片
双向排序(Java)_第2张图片

分析

AcWing双向排序

依据题意,一共有两种操作:

  1. 对序列的前缀进行倒序排
  2. 对序列的后缀进行正序排

需要观察到这样的操作有以下性质:

  1. 如果第一次进行的操作2,则该次操作是无效操作。
    因为原来就是正序。
  2. 当有连续统一个操作时,取区间最长的操作即可
    因为短的操作相当于在长的操作内部进行排序,最终结果跟一次性在最长的区间进行排序是一致的。
  3. 当操作交替出现时:

3.1 能够观察到,只有红色部分是发生了变化的,其他的部分都是直接抄下来

双向排序(Java)_第3张图片
3.2 如果操作的区间变短,那需要变化的区间也就越小

双向排序(Java)_第4张图片
3.3 如果操作的区间变长,那其之前比当前操作区间短的操作一和操作二都可以省略
比如该图中删除①和②,直接进行③,得到的结果是一样的,原因是A、B段必定是小于C段的,因此前面①②相当于是在内部打乱了
双向排序(Java)_第5张图片

import java.util.Scanner;

public class Main {
	final static int N = 100010;
	
	static class opt{
		int p,q;
		public opt(int p, int q) {
			// TODO Auto-generated constructor stub
			this.p = p;
			this.q = q;
		}
	}
	static opt stk[] = new opt[N];
	
	static int ans[] = new int[N];
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n,m;
		n = sc.nextInt();
		m = sc.nextInt();
		int p,q;
		int top = 0;
		for(int i = 0; i < m; i++) {
			p = sc.nextInt();
			q = sc.nextInt();
			//操作1
			if(p == 0) {
				//连续的操作1
				while(top != 0 && stk[top].p == 0)
					q = Math.max(q, stk[top--].q);
				//把前面比当前操作1范围小的操作1和操作2删除
				while(top >= 2 && stk[top-1].q <= q)
					top-=2;
				//保存本次操作
				stk[++top] = new opt(0, q);
				
			}else if(top != 0) {
				while(top != 0 && stk[top].p == 1)
					q = Math.min(q, stk[top--].q);
				while(top >= 2 && stk[top-1].q >= q)
					top -=2;
				stk[++top] = new opt(1, q);
			}
		}
		int k = n, l = 1, r = n;
		for(int i = 1; i <= top; i++) {
			if(stk[i].p == 0)
				while(r > stk[i].q && l <= r)
					ans[r--] = k--;
			else
				while(l < stk[i].q && l <= r)
					ans[l++] = k--;
			if(l > r)
				break;
		}
		if(top % 2 == 1)
			while(l <= r)
				ans[l++] = k--;
		else
			while(l <= r)
				ans[r--] = k--;
		for(int i = 1; i <= n ;i++)
			System.out.print(ans[i] + " ");
	}
}

你可能感兴趣的:(java)