在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++