题意:
给出一个长为n的序列和m次操作,指令r中1表示排非减增序列,2表示排非增减序列,t表示从1到位置t的数按照指令r的要求排序。
思路:
对于排序来说如果t大于前面的t那么,前面的排序都是无用的。知道了这点就可以用一个单调栈来维护操作,使得最后需要进行的操作都是必须的且t按降序排列。
而对于后面的操作,必须要在前面已经排好的序列下进行,所以必须是从前向后进行操作。而t是从大到小排序的,所以当t减小时,就能确定一些数不在进行任何的排序了。所以每次只要确定下来不在排序的数即可。这样时间复杂度可以降到O(n)。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=200005;
struct stru
{
int r,t;
}p[maxn],tmp;
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
int n,m;
int a[maxn],b[maxn];
while(~scanf("%d%d",&n,&m))
{
int top=0,siz=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&tmp.r,&tmp.t);
while(siz>0&&p[top].t<tmp.t)
{
top--;
siz--;
}
if(siz>0&&p[top].r==tmp.r)
continue;
p[++top]=tmp;
siz++;
}
if(p[1].r==1)
sort(a+1,a+1+p[1].t);
else
sort(a+1,a+1+p[1].t,cmp);
for(int i=1;i<=n;i++)
b[i]=a[i];
int r=p[1].t,l=1;
if(p[1].r==1)//l和r怎么对应b数组与一开始升序还是降序有关
{
for(int i=2;i<=siz;i++)
{
if(p[i-1].r==1)
{
for(int j=p[i-1].t;j>p[i].t;j--)
{
b[j]=a[r--];
}
}
else
{
for(int j=p[i-1].t;j>p[i].t;j--)
{
b[j]=a[l++];
}
}
}
if(p[siz].r==1)
for(int i=p[siz].t;i>=1;i--)
{
b[i]=a[r--];
}
else
for(int i=p[siz].t;i>=1;i--)
{
b[i]=a[l++];
}
}
else
{
for(int i=2;i<=siz;i++)
{
if(p[i-1].r==1)
{
for(int j=p[i-1].t;j>p[i].t;j--)
{
b[j]=a[l++];
}
}
else
{
for(int j=p[i-1].t;j>p[i].t;j--)
{
b[j]=a[r--];
}
}
}
if(p[siz].r==1)
for(int i=p[siz].t;i>=1;i--)
{
b[i]=a[l++];
}
else
for(int i=p[siz].t;i>=1;i--)
{
b[i]=a[r--];
}
}
for(int i=1;i<=n;i++)
{
if(i==1)
printf("%d",b[i]);
else
printf(" %d",b[i]);
}
printf("\n");
}
return 0;
}