线段树合并、分裂
基本概念:
如果需要維護許多個大小為 \(10^5\) 級別的多重集,可以看做給每一個多重集建立一棵線段樹。線段樹的合并、分裂就是多重集的累加、分開。
這里使用動態開點的方式存儲線段樹樹。
如果一個節點為空,那么它的編號為 \(0\) 。
變量釋義:
-
有 \(cnt\) 個多重集
-
建立了 \(tot\) 個節點
-
若一個多重集的編號為 \(x\) ,它的根節點編號為 \(root[x]\)
注意:空間是個謎!能開多大是多大
線段樹合并
把以 \(y\) 為根的線段樹合并到以 \(x\) 為根的線段樹:
int merge(int x,int y,int nl,int nr) // i:y->x {if(!x || !y) return x+y;int mid=(nl+nr)>>1;//tree[x].sum+=tree[y].sum; 根據題目改動tree[x].ls=merge(tree[x].ls,tree[y].ls,nl,mid);tree[x].rs=merge(tree[x].rs,tree[y].rs,mid+1,nr);//pushup(x);del(y);return x; }復雜度 \(=\) 節點數 ( 一般均攤下來可以達到一次操作 \(O(\log n)\) 的級別 )
線段樹分裂
把以 \(x\) 為根的線段樹中 \(\ge k\) 的數轉移到一棵 空的 線段樹 \(y\) 。
void split(int &x,int &y,int nl,int nr,int k) // i>=k i:x->y {if(!x) x=++tot;if(!y) y=++tot;if(nl==nr) { swap(x,y); return; }int mid=(nl+nr)>>1;if(mid>=k){swap(tree[x].rs,tree[y].rs);split(tree[x].ls,tree[y].ls,nl,mid,k);}else split(tree[x].rs,tree[y].rs,mid+1,nr,k);pushup(x),pushup(y); }例題:
P5494 【模板】線段樹分裂 \(\rightarrow\) 模板代碼
總結
- 上一篇: 让自己人生观更清晰让自己人生观更清晰的书
- 下一篇: 【做题记录】CF1428E Carrot