洛谷P5055 模板 可持久化文藝平衡樹

2022-06-13 14:18:10 字數 1683 閱讀 7362

您需要寫一種資料結構,來維護乙個序列,其中需要提供以下操作(對於各個以往的歷史版本):

在第 \(p\) 個數後插入數 \(x\) 。

刪除第 \(p\) 個數。

翻轉區間 \([l,r]\),例如原序列是 \(\\),翻轉區間 \([2,4]\) 後,結果是 \(\\)。

查詢區間 \([l,r]\) 中所有數的和。

和原本平衡樹不同的一點是,每一次的任何操作都是基於某乙個歷史版本,同時生成乙個新的版本(操作 \(4\) 即保持原版本無變化),新版本即編號為此次操作的序號。

\(n\leq 2\times 10^5,|x|\leq 10^6\)。

ftq treap 維護區間操作十分簡單:直接把前 \(r\) split 出來,再把前 \(l-1\) 規範 split 出來,就得到 \([l,r]\) 了。

所以我們可以像 splay 一樣進行區間翻轉,維護區間和。

但是注意除了在 split 和 merge 處要複製節點以外,在 pushdown 處也要複製節點。因為可能出現下圖的情況

其中 \(y\) 是 \(x\) 複製過來的節點,假設 \(y\) 有翻轉標記且此時我們 pushdown \(y\),那麼就會把 \(x\) 的兒子給翻轉。下次詢問 \(x\) 的資訊時就會出錯。

所以為了方便 pushdown,fhq treap 乙個節點的翻轉標記表示這個點的兩個兒子還沒有被翻轉。也就是 pushdown \(x\) 時需要翻轉 \(x\) 的左右兒子,同時下傳標記。

空間往大的開就行了。

時間複雜度 \(o(n\log n)\)。

#include using namespace std;

typedef long long ll;

const int n=200010,maxn=n*100;

int n,rt[n];

ll last;

struct fhq

void pushup(int x)

void pushdown(int x) }

int new(int v)

void split(int x,int k,int &lc,int &rc)

pushdown(x);

int y=cpynode(x);

if (siz[ch[y][0]]>=k)

rc=y,split(ch[y][0],k,lc,ch[y][0]);

else

lc=y,split(ch[y][1],k-siz[ch[x][0]]-1,ch[y][1],rc);

pushup(y); }

int merge(int x,int y)

else

}void ins(int &root,int k,int v)

void del(int &root,int k)

void reverse(int &root,int l,int r)

ll query(int &root,int l,int r)

}fhq;

int main()

return 0;

}

P5055 模板 可持久化文藝平衡樹

突然發現fhq treap也是可以支援區間翻轉的,所以基本上和其他平衡樹是一樣的,而且還滿足重量平衡樹的性質,真是太優秀了,只不過常數稍微比較大。然後這裡我們變成了一顆區間平衡樹,需要支援以下幾個操作。若 opti 1,則接下來兩個整數 pi,xi 表示操作為在第 pi個數後插入數 x。若 opti...

洛谷P3919 模板 可持久化陣列

題目大意 有兩個操作,1 在第x次操作後的版本上修改乙個值,2 查詢在第x次操作後的版本上的乙個節點的值 即 你需要維護這樣的乙個長度為n的陣列,支援如下幾種操作 1.在某個歷史版本上修改某乙個位置上的值 2.訪問某個歷史版本上的某一位置的值 此外,每進行一次操作 對於操作2,即為生成乙個完全一樣的...

洛谷P3835 模板 可持久化平衡樹

本題為題目 普通平衡樹 的可持久化加強版。資料已經經過強化 插入x數 刪除x數 若有多個相同的數,因只刪除乙個,如果沒有請忽略該操作 查詢x數的排名 排名定義為比當前數小的數的個數 1。若有多個相同的數,因輸出最小的排名 查詢排名為x的數 求x的前驅 前驅定義為小於x,且最大的數,如不存在輸出 21...