您需要寫一種資料結構,來維護乙個序列,其中需要提供以下操作(對於各個以往的歷史版本):
在第 \(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...