洛谷P3391 文藝平衡樹 Splay

2022-05-22 19:09:06 字數 1647 閱讀 9787

時間限制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

fa)

然後就開始翻轉了。。。實際上翻轉操作的話我們只需要將l-1伸展到根結點,r+1伸展到根結點的右兒子,那麼剩下的就是區間[l,r]了:

我們找到l~r的第一結點打上標記後下傳,對於有標記的我們直接翻轉左右兒子就達到翻轉的效果了。至於l~r的第一結點位置就很好找,它是根結點的右兒子的左兒子。

於是我們的翻轉操作就可以完美寫出來了:

void reverse(int l,int

r)

然後套個splay的板子,find(x)是指找到x所在樹中的位置,類似於權值線段樹的寫法:

int find(int x)//

找到x所在的結點}}

以下是ac**:

#include #include 

#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;

}

view code

洛谷 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為...