時間限制1.00s
記憶體限制125.00mb
您需要寫一種資料結構(可參考題目標題),來維護乙個有序數列。
其中需要提供以下操作:翻轉乙個區間,例如原有序序列是 54321,翻轉區間是 [2,4]的話,結果是 52341。
第一行兩個正整數 n,m表示序列長度與操作個數。序列中第 i項初始為 i。
接下來 m 行,每行兩個正整數 l,r,表示翻轉的區間。
輸出一行 n個正整數,表示原始序列經過 m次變換後的結果。
輸入
5 3輸出1 31 3
1 4
4 3 2 1 5【資料範圍】
對於 100% 的資料,1≤n,m≤100000,1≤l≤r≤n。
emmm,沒什麼好說的,上來就是個splay板子,然後想想,如果按照它原來的順序建樹的話就是一條只有右兒子的鏈。我們考慮使用線段樹的方式,一直找中點,就可以使得它的深度接近完美:
int build(int l,int r,int然後就開始翻轉了。。。實際上翻轉操作的話我們只需要將l-1伸展到根結點,r+1伸展到根結點的右兒子,那麼剩下的就是區間[l,r]了:fa)
我們找到l~r的第一結點打上標記後下傳,對於有標記的我們直接翻轉左右兒子就達到翻轉的效果了。至於l~r的第一結點位置就很好找,它是根結點的右兒子的左兒子。
於是我們的翻轉操作就可以完美寫出來了:
void reverse(int l,int然後套個splay的板子,find(x)是指找到x所在樹中的位置,類似於權值線段樹的寫法:r)
int find(int x)//以下是ac**:找到x所在的結點}}
#include #includeview code#include
using
namespace
std;
const
int mac=1e5+10
;struct
tree
tree[mac];
introot,num,a[mac],_min,_max;
void update(int
rt)int build(int l,int r,int
fa)void push_down(int rt)//
傳下旋轉標記
int find(int x)//
找到x所在的結點
}}bool which(int x)//
判斷x是左右兒子的哪乙個
void rotate(int
rt)void splay(int rt,int goal)//
將rt伸展為goal的兒子
if (goal==0) root=rt;
}void reverse(int l,int
r)void mid_dfs(int rt)//
中序遍歷輸出
intmain()
mid_dfs(root);
printf("\n
");return0;
}
洛谷 P3391 文藝平衡樹
您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 翻轉乙個區間,例如原有序序列是5 4 3 2 1,翻轉區間是 2,4 的話,結果是5 2 3 4 1 輸入格式 第一行為n,m n表示初始序列有n個數,這個序列依次是 1,2 n 1,n m表示翻轉操作次數 接下來m行每...
洛谷P3391 文藝平衡樹
傳送門 to luogu 題外話 一開始用splay text splay 寫了一發,結果 然後就換成了treap text treap 嗯,無旋treap text treap 直接用split text split 把 l,r l,r l,r 割下來,然後打標記。當然,因為翻轉之後將不滿足二叉搜...
洛谷 P3391 文藝平衡樹
by洛谷 裸的平衡樹反轉 方法是按序列位置為關鍵字排序 反轉 l,r 則將l 1置於根處,將r 1作為根的右兒子,這樣,r 1的左子樹就是需要反轉的區間 然後對r 1的左兒子,反轉其左右兒子,並打上線段樹一樣的lazy標記,待以後反轉她的子樹 一開始,企圖把位置維護為關鍵字,然後排序 這樣,若點a為...