在2016年,佳媛姐姐喜欢上了数字序列。php
于是她常常研究关于序列的一些奇奇怪怪的问题,如今她在研究一个难题,须要你来帮助她。c++
这个难题是这样子的:给出一个1到n的全排列,如今对这个全排列序列进行m次局部排序,排序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q位置上的数字。spa
输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。
第二行为n个整数,表示1到n的一个全排列。
接下来输入m行,每一行有三个整数op,l,r,op为0表明升序排序,op为1表明降序排序,l,r表示排序的区间。
最后输入一个整数q,q表示排序完以后询问的位置。blog
输出数据仅有一行,一个整数,表示按照顺序将所有的部分排序结束后第q位置上的数字。排序
样例输入内存
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3get
样例输出it
5class
$1\leqslant n,m\leqslant {10}^5$方法
$1\leqslant q\leqslant n$
它放在了“不打正解的我”这一板块,正解是线段树,时间复杂度$\Theta (m\log^2n)$。
确实,这道题我打的暴力。
首先考虑暴力sort,时间复杂度:$\Theta (m\times n\log n)$。
可是,$10^5$的数据范围显然跑不过,因而我便想到了一个并不经常使用的排序方法:桶排序。
这道题保证了这$n$个数是$n$的全排列,因而桶排序可行。
可是稳妥的桶排序在统计答案的时候须要扫整个区间,在$m$次询问后时间复杂度会变为$\Theta (n\times m)$,显然有不可作了。
那么我在往桶里放数的时候标记一下放进去的最大值和最小值,而后在往外拿的时候只扫描这个区间,成功卡过,甚至比某些打的不怎么优秀的线段树还要快。
码长和内存才是亮点。
#include<bits/stdc++.h>
using namespace std;
int a[100001],t[100001];
void change0(int l,int r)//升序
{
int maxn=0,minn=20020923,flag=l;
for(int i=l;i<=r;i++)
{
t[a[i]]=1;
minn=min(minn,a[i]);
maxn=max(maxn,a[i]);
}
for(int i=minn;i<=maxn;i++)
if(t[i])a[flag++]=i,t[i]=0;
}
void change1(int l,int r)//降序
{
int maxn=0,minn=20020923,flag=l;
for(int i=l;i<=r;i++)
{
t[a[i]]=1;
minn=min(minn,a[i]);
maxn=max(maxn,a[i]);
}
for(int i=maxn;i>=minn;i--)
if(t[i])a[flag++]=i,t[i]=0;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
while(m--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op)change1(l,r);
else change0(l,r);
}
scanf("%d",&n);
printf("%d",a[n]);
return 0;
}
rp++