题目链接
转载自
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 mmanagers. 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 ≤ 200 000) — 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.
Output
Print n integers — the final report, which will be passed to Blake by manager number m.
Examples
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
Note
In the first sample, the initial report looked like: 1 2 3. After the first manager the first two numbers were transposed: 2 1 3. The report got to Blake in this form.
In the second sample the original report was like this: 1 2 4 3. After the first manager the report changed to: 4 2 1 3. After the second manager the report changed to: 2 4 1 3. This report was handed over to Blake.
题意:给出n个无序的数以及m个操作,每个操作由两个数组成,第一个数是操作的方式,第二个数 i 是操作的范围,若第一个数是1,则给 1-i 个数按升序排序,若第二个数是2,则给 1-i 个数按降序排列。输出所有操作完成后的序列。
思路:一道思维题,肯定不能直接一个个排序,重复操作次数太多肯定超时。
首先我们可以想到,如果下一个操作的区间比上一个要大,那么上一个操作将会是无效的,如下面两个操作:
1 5
2 8
先给前5个数按升序排列,再给前8个数按降序排列,那么第一个的升序排列就被第二个降序排列给覆盖了,所以第一个操作实际上是多余的。
所以我们可以删除那些不必要的操作来节约时间。那怎么删除呢?首先我们要找出所有操作中区间最大的操作,因为在这之前的操作都是不必要的;然后再找出这步操作之后区间最大的操作,一直如此,直到找完所有的操作。
最后我们筛选出的操作的区间就如下面的线段所示:
————————
——————
————
——
操作的区间逐渐递减,且都是不会被完全覆盖的关键操作。那具体如何筛选出关键操作:
我们首先声明一个数组t【20000】来存关键操作,数组初始化的第一个元素就是输入的第一个操作,然后遍历所有操作,如果你当前遍历到的操作,他的区间小于t数组中存下的最后一个操作,就把当前操作存入数组;否则就删除所有数组中区间比当前小的操作。因为你存储操作的过程中,只会存下比数组中操作区间小的,数组中比当前遍历到的操作小的都被删除了,所以你最后得到的一定是一个递减的关键操作序列。
但是,筛选出了关键操作还不够,还要继续优化:
假如总共给出了10个数,而最大的操作是:1 5,那么我们可以知道,答案序列的最后5个数一定和初始序列相同,因为没有操作会对后5个数进行操作,所以可以直接将后五个数存到ans数组的后5位。
接下来,看下面两个操作:
1 7
2 4
对于第一个操作,我们只需要确定5,6,7三个位置的值,因为前四个数会被下一个操作所影响,排了也是无效的。、
且确定5,6,7三个位置的值也很简单,我们先将最大操作区间内的所有数按升序排好,然后根据上面两个操作,第一个是1 7,第二个数2 4,因为第一个操作是升序,且只有5,6,7位置有效,那我们就可以在之前排好序的序列中选出最大的三个数放到ans中5,6,7的位置,然后在序列中删去这三个最大的数;如果是降序排也同理,选出最小的几个数放入ans即可。
下面看代码:
题目意思:先输入两个数字n,m,n表示要输入n个数字,m表示有m次操作
在m次操作中,输入两个a,b
当a为1时,表示将1-b的数字进行升序操作
当a为2时,表示将1-b的数字进行降序操作。
思路:正常的sort,或者优先队列都会超时。
代码: 参考代码
栈的写法,首先对于不同位置的操作,显然对于第ii个操作,若有第jj个操作(1<=j
#include
代码2:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-7
#define ll long long
#define inf 0x3f3f3f3f
#define pi 3.141592653589793238462643383279
using namespace std;
struct node{
int oper,end;
}b[200007]; //用来存操作
int n,m,a[200007],ans[200007];
int main()
{
cin>>n>>m;
for(int i=1; i<=n; ++i)
scanf("%d",&a[i]);
int sum=1,t[200007];
scanf("%d%d",&b[1].oper,&b[1].end);
t[sum++] = 1; //初始化关键操作为第一个操作
for(int i=2; i<=m; ++i)
{
scanf("%d%d",&b[i].oper,&b[i].end); //2降序,1升序
while( b[t[sum-1]].end <= b[i].end && sum > 1) //如果当前操作比存下的关键操作中的最后一个还关建,那就删去
{
sum--;
}
t[sum++] = i; //将所有不如自己关键的操作删去后,将自己存入
}
for(int i=n; i>=b[t[1]].end+1; i--) ans[i] = a[i]; //将最大操作区间之后的数直接存入ans数组
sort(a+1,a+1+b[t[1]].end); //个最大操作区间内的数排好序
int low = 1,high = b[t[1]].end; //用来确定剩下的数的范围
for(int i=2; i=b[t[i]].end+1; --j)
ans[j] = a[high--];
}
else
{
for(int j=b[t[i-1]].end; j>=b[t[i]].end+1; --j)
ans[j] = a[low++];
}
}
for(int i=1; i<=b[t[sum-1]].end; ++i) //在剩下的最后一个操作的区间内放入剩下的数
{
if(b[t[sum-1]].oper==2)
ans[i] = a[high--];
else
ans[i] = a[low++];
}
for(int i=1; i<=n; ++i)
printf("%d%c",ans[i],i==n ? '\n' : ' ');
return 0;
}
/*
10 5
1 6 9 4 3 5 12 11 2 7
1 9
2 4
2 6
1 7
2 5
*/