CF#344 div2 C.Report(思维)

原题描述:

Each month Blake gets the report containing main economic indicators of the company "Blake Technologies". There are n commodities produced by the company. For each of them there is exactly one integer in the final report, that denotes corresponding revenue. Before the report gets to Blake, it passes through the hands of m managers. Each of them may reorder the elements in some order. Namely, the i-th manager either sorts first ri numbers in non-descending or non-ascending order and then passes the report to the manager i+1, or directly to Blake (if this manager has number i=m).

Employees of the "Blake Technologies" are preparing the report right now. You know the initial sequence ai of length n and the description of each manager, that is value ri and his favourite order. You are asked to speed up the process and determine how the final report will look like.

Input

The first line of the input contains two integers n and m (1≤n,m≤200000)− the number of commodities in the report and the number of managers, respectively.

The second line contains n integers ai (|ai|≤109)− the initial report before it gets to the first manager.

Then follow m lines with the descriptions of the operations managers are going to perform. The i-th of these lines contains two integers ti and ri (, 1≤ri≤n), meaning that the i-th manager sorts the first ri numbers either in the non-descending (if ti=1) or non-ascending (if ti=2) order.

Example

Input

3 1
1 2 3
2 2

Output

2 1 3 

Input

4 2
1 2 4 3
2 3
1 2

Output

2 4 1 3 

题目大意:给出n个数,m个操作。输入a,b,a为操作种类,b为操作位置。2种操作:

1.1到b从小到大排序

2.从1到b从大到小排序。最后输出最终操作后的数组。

思路

就别想直接sort了.

思路其实很容易想出来,b值大的排序会覆盖掉前面所有比他小的排序,这样就能省去很多无用的sort,难的是如何优雅的写出来代码.

先来看看我写的半吊子 TLE 代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 200010;
int a[maxn], ans[maxn], maxi, maxb, pos, tot;
struct Caozuo{ int num, flag, b; }c[maxn];//记录操作,num表示是第几次,flag表示种类
bool cmpcz(Caozuo a, Caozuo b){ return a.b > b.b; }//降序排列操作
bool cmp(int a, int b){ return a > b; }//降序排列原序列
int main(){
	int n, m; scanf("%d%d", &n, &m);
	for(int i=1; i<=n; i++) scanf("%d", &a[i]);
	for(int i=1; i<=m ;i++){ 
		scanf("%d%d", &c[i].flag, &c[i].b); 
		c[i].num = i; 
	}
	sort(c+1, c+1+m, cmpcz);//按照b值降序排列操作
	maxi = c[1].num; ans[++tot] = 1;//maxi记录要进行的操作中序号最大的那个,ans记录要进行的操作的下标
	for(int i=2; i<=m; i++){
		if(c[i].num > maxi && !(c[i].flag == c[ans[tot]].flag && c[i].num == c[ans[tot]].num+1)){
            //一个操作的b值即使最大,序号在他后面的操作还是会造成影响
            //第一个条件是保证当前的操作序号在上一次操作的后面
            //第二个条件是,如果这两次操作相邻,又是同类的操作,就没必要进行两次
			ans[++tot] = i;//记录下标
			maxi = c[i].num;//maxi改为当前操作的序号
		}
		if(c[i].num == m) break;//已经到了最后一次操作,那全部操作已经覆盖完全
	}
	for(int i=1; i<=tot; i++){//只进行我们筛选出来的有用的操作
		int flag = c[ans[i]].flag, b = c[ans[i]].b;
		if(flag == 1) sort(a+1, a+1+b);
		else sort(a+1, a+1+b, cmp);
	}
	for(int i=1; i<=n; i++) printf("%d ", a[i]);
	return 0;
}  

会在第22个点t掉, ........

如何改进?

去查了大佬用栈写的代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
stack<int> s;
int n, m, tot=0, a[maxn], b[maxn], flag[maxn], r[maxn], ans[maxn];
bool cmp(int a, int b){ return a > b; }
int main(){
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; ++i) scanf("%d",&a[i]), b[i] = a[i];//复制一下
	for(int i=1; i<=m; ++i){
		scanf("%d%d", &flag[i], &r[i]);
		while(!s.empty() && r[s.top()] < r[i]) s.pop();//栈顶的b值小于当前操作
		s.push(i);//当前操作入栈
	}
	while(!s.empty()){
		ans[++tot] = s.top();//记录筛选出的操作
		s.pop();
	}
	int left = 1, right = r[ans[tot]];//right是筛选出的第一次操作的b值
	sort(b+1, b+1+r[ans[tot]]);//下面这段有点难理解,也是精髓
	for(int i=tot-1; i>=0; --i){//按序号从前往后,枚举当前操作的下一次操作,b值一定是递减的
		for(int j=r[ans[i+1]]; j>r[ans[i]]; --j)//j枚举了两次操作相差的那一段(前这次操作比下一次操作多出来的那一段)
			if(flag[ans[i+1]] == 1) a[j] = b[right--];//如果当前操作为1, 直接把排好序的b中那个位置的数拿过来.右边界--,这一段不会受后面影响了
			else a[j] = b[left++];//同理
	}
	for(int i=1; i<=n; ++i) printf("%d ",a[i]);
}

原文地址:https://www.cnblogs.com/hzoi-poozhai/p/12806825.html