BZOJ3223 Tyvj 1729 文藝平衡樹

2022-05-25 22:33:13 字數 1391 閱讀 4136

第一行為n,m n表示初始序列有n個數,這個序列依次是(1,2……n-1,n) m表示翻轉操作次數

接下來m行每行兩個數[l,r] 資料保證 1<=l<=r<=n

輸出一行n個數字,表示原始序列經過m次變換後的結果

5 31 3

1 31 4

4 3 2 1 5

n,m<=100000

模板splay(不帶區間操作)是按照權值來排序維護二叉查詢樹的。如果把splay推廣到區間操作,我們需要進行一些修改。把乙個元素在區間中的下標(即第幾個)作為splay樹的權值。所以對於這棵splay樹的根節點,左邊的所有節點在序列中的位置都在根節點之前。這樣如果我們需要操作區間\([l,r]\),我們就先把l-1轉到root,再把r+1轉到root的右兒子,那麼root的右兒子的左子樹則是區間\([l,r]\)對應的所有節點。splay樹中排名為k的節點則是序列中第k個節點。

我們可以發現,對於乙個子樹,子樹的根節點的左子樹就是在根節點左側的點,右子樹就是在根節點右側的點。那麼我們容易發現,如果把左右子樹換一下,然後遞迴的更新左右子樹即可。

為了優化時間,我們可以像線段樹一樣打個tag來維護翻轉操作。同時push_down操作就是下傳tag同時交換左右子樹。

#include#include#include#include#define maxn (int)(1e5+1000)

#define inf (int)(1e9+1000)

using namespace std;

intval[maxn],tag[maxn],size[maxn],son[maxn][2],fa[maxn],cnt[maxn],s[maxn];

int n,m,idx,root;

void push_down(int x)

if(son[x][1])

tag[x]=0;

swap(son[x][0],son[x][1]);

return;

}void push_up(int x)

if(son[x][1])

return;

}void down(int x)

void rotate(int x)

void splay(int x,int v=0)

if(!v)root=x;

}void insert(int x,int a)

if(size[son[x][0]]+cnt[x]>=a)

return kth(son[x][1],a-cnt[x]-size[son[x][0]]);

}void write(int x)

int main()

for(int i=1;i<=m;i++)

write(root);

return 0;

}

bzoj3223 Tyvj 1729 文藝平衡樹

傳送門 description input 第一行為n,m n表示初始序列有n個數,這個序列依次是 1,2 n 1,n m表示翻轉操作次數 接下來m行每行兩個數 l,r 資料保證 1 l r n output 輸出一行n個數字,表示原始序列經過m次變換後的結果 sample input 5 31 3...

BZOJ3223 Tyvj1729 文藝平衡樹

題目大意 一開始有個數列 有q 次區間翻轉操作。請輸出最後的序列。1 n,q 105一道寫出blog都不知道有什麼意義的splay大裸題。splay在我還是pas黨的時候寫過,現在已經忘了個精光。就當做是模板記錄,以及作為自己終於下定決心怒剛專題的紀念吧。什麼你告訴我你不知道這題怎麼做?那我也沒辦法...

bzoj3223 Tyvj1729 文藝平衡樹

time limit 10 secmemory limit 128 mb submit 3014solved 1722 您需要寫一種資料結構 可參考題目標題 來維護乙個有序數列,其中需要提供以下操作 翻轉乙個區間,例如原有序序列是54321,翻轉區間是 2,4 的話,結果是52341 第一行為n,m...