【heoi2016/tjoi】排序
在2023年,佳媛姐姐喜歡上了數字序列。因而他經常研究關於序列的一些奇奇怪怪的問題,現在他在研究乙個難題,需要你來幫助他。這個難題是這樣子的:給出乙個1到n的全排列,現在對這個全排列序列進行m次區域性排序,排序分為兩種:1:(0,l,r)表示將區間[l,r]的數字公升序排序2:(1,l,r)表示將區間[l,r]的數字降序排序最後詢問第q位置上的數字。
輸入資料的第一行為兩個整數n和m。n表示序列的長度,m表示區域性排序的次數。第二行為n個整數,表示1到n的乙個全排列。接下來輸入m行,每一行有三個整數op, l, r, op為0代表公升序排序,op為1代表降序排序, l, r 表示排序的區間。最後輸入乙個整數q,q表示排序完之後詢問的位置
輸出資料僅有一行,乙個整數,表示按照順序將全部的部分排序結束後第q位置上的數字。
輸入 #1複製
6 31 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
輸出 #1複製
5
河北省選2016第一天第二題。
對於30%的資料,n,m\leq 1000n,m≤1000
對於100%的資料,n,m\leq 10^5n,m≤105且始終1\leq q\leq n1≤q≤n
題意簡單明瞭,但題目給了我乙個很棒的思路。
先想想暴力該怎麼打。
排序?我們看到了n的取值範圍只有1e5,這顯然給桶排帶來了無限生機。記錄下區間的min和max,這題可以暴力出80分的好成績。
雖然80分對我來說已經夠了, 但是100分總是那麼誘人。
我們觀察題目中給出的一些特殊性質。
1、 對於[1,n]中每個元素只出現一次。
2、 查詢只有1次。
這兩個性質足夠我們打出正解了。
首先答案一定在[1,n]中。能不能二分答案?
我們把操作離線,對於每個mid進行check。
如何check?首先,我們把原序列中大於等於mid的標為1,小於mid的記做0。
這樣我們一趟排序下來,如果pos(查詢的位置)為1,這代表說,pos是大於等於mid的,答案一定在[mid,r]中。
反之,答案一定在[l,mid-1]中。
那麼這樣做好在**呢?
對於普通排序,頂多做到o(n),然而對於0,1序列的排序,可以做到o(log n)。
如何操作?
可以使用強大的線段樹。線段樹的區間查詢,區間修改,可以用於0,1序列的排序。
當對乙個區間進行排序時,首先query出這個區間裡1的個數,也就是區間和,記做cnt。
若是降序排列,則把區間[l,l+cnt-1]修改為1,[l+cnt,r]修改為0。
若是公升序排列,則把區間[r-cnt+1,r]修改為1,[l,r-cnt]修改為0。
上面就是基於線段樹對0,1串的排序。
總體時間複雜度o(mlognlogn)
線段樹的功能十分強大,區間修改是線段樹最重要的功能之一,好好學習和運用,會有很大的幫助。
#include#include#include
#define ls (k<<1)
#define rs (k<<1|1)
using
namespace
std;
const
int n=1e5+10
;int tree[n<<2],tag[n<<2],a[n],op[n][5
];//原先因為tag忘開4倍空間只有80分,給自己長個記性。
intn,m,pos;
inline
void read(int &x)
inline
void build(int k,int x,int y,int
val)
int mid=x+y>>1
; build(ls,x,mid,val);
build(rs,mid+1
,y,val);
tree[k]=tree[ls]+tree[rs];
}inline
void update(int k,int x,int
y)inline
int query(int k,int x,int y,int l,int
r)inline
void change(int k,int x,int y,int l,int r,int
val)
if(tag[k]!=-1
) update(k,x,y);
int mid=x+y>>1
; change(ls,x,mid,l,r,val);
change(rs,mid+1
,y,l,r,val);
tree[k]=tree[ls]+tree[rs];
}inline
bool check(int
x)
else
}return query(1,1
,n,pos,pos);
}int
main()
printf("%d
",ans);
}
題解 洛谷 P2824 排序
乍一看這道題跟cf558e長得非常像,我們能否採用解決這道題的方法來解決這道題呢?答案 不行。cf558e那道題排序過程之所以能用線段樹維護是因為排序的值域是確定的,只有26,因此我們暴力開26棵線段樹維護狀態沒有問題。但是這道題顯然就不行了,值域為n,我們開不下。這時我們的思路就向cf558e那道...
09 排序1 排序
09 排序1 排序 25 分 給定n 個 長整型範圍內的 整數,要求輸出從小到大排序後的結果。本題旨在測試各種不同的排序演算法在各種資料情況下的表現。各組測試資料特點如下 include include includeusing namespace std const int cutoff 1000...
09 排序1 排序
n個 長整型範圍內的 整數,要求輸出從小到大排序後的結果。資料2 11個不相同的整數,測試基本正確性 資料3 10 3個隨機整數 資料4 10 4個隨機整數 資料5 10 5個隨機整數 資料6 10 5個順序整數 資料7 10 5個逆序整數 資料8 10 5個基本有序的整數 資料9 10 5個隨機正...