Noip前的大抱佛腳----資料結構
資料結構
線段樹
注意:空間開4倍
神奇標記
From8.26 Test_zsy(CPU監控)
如果一個點權為\(val\)的點被打上了\((a,b)\)標記,那麼他的實際點權為\(max(a+val,b)\)
幹啥滴?
標記不下放
- 區間加標記不下放,維護區間max或者最大值
方法是當前\(tag\)維護當前區域標記,\(t\)維護左右兒子的\(max+tag[now]\),並沒有快多少,如果仍然忘記見提交記錄
並查集
維護二分圖
並查集每個點維護是否要改顏色,然後按秩合併/按大小合併即可
實際上可以說是用期望樹高為\(logn\)的樹形結構維護資訊
維護後繼位置
快速得到後繼位置
[BZOJ2054]瘋狂的饅頭 維護數列的後繼位置
對一個數列進行\(10^7\)次區間覆蓋,查詢最終顏色。
倒序做,每次做完一個區間把\([l,r]\)的並查集父親指向\(r+1\),表示掃到該區間,要從\(r+1\)開始染色,這樣就可以快速得到下一個染色的位置,複雜度為\(O(n)\)
[BZOJ2238]Mst 維護樹形結構的後繼位置
對樹上路徑進行染色,查詢最終顏色。
路徑拆成直上直下的兩條,\(x,lca、y,lca\),於是每次弄完把\([x,lca]\)的並查集父親指向\(fa[lca]\),就可以類似數列一樣快速求得下一個位置了,複雜度為\(O(n)\)
堆
對於所有的父子結構,一定都有父親的優先順序大於左右兒子的優先順序
可並堆的可持久化
左偏樹可持久化,每次合併兩個堆,只需要給經過的\(log\)個結點複製一遍就好了
#define lc H[x].ch[0] #define rc H[x].ch[1] struct heap {int ch[2],dis;double w;}H[M]; int Merge(int x,int y) { if(!x||!y) return x+y; H[++node]=H[x];x=node; if(H[x].w>H[y].w) swap(x,y); rc=Merge(rc,y); if(H[lc].dis<H[rc].dis) swap(lc,rc); H[x].dis=H[rc].dis+1; return x; }
這個可以用來完成\(k\)短路問題
dsu on tree
姑且叫它資料結構
方式&原理
步驟:
- 先遞迴做輕兒子的答案,再遞迴做重兒子的答案
- 暴力把當前結點的輕兒子掃一遍統計答案
- 如果當前結點是遞迴下來的輕兒子,掃一遍把答案清空,否則不做處理
要求: 離線演算法
複雜度: \(O(nlogn)\)
分析:只需要考慮每個點被掃的次數,樹剖下來每個點到根的路徑最多有\(log\)條鏈,每逢輕重鏈交替的時候就會暴力去掃,於是每個點最多隻會被掃\(log\)次,複雜度得證
適用範圍
適用一些子樹資訊不好統計的題,可以類比於樹上莫隊
統計子樹內數量最多的顏色的編號之和(Codeforces600E)
統計子樹內距離\(i\)點不超過\(k\)的點的顏色數/某權值之和(BZOJ4771七彩樹離線版/[湖南集訓]談笑風生)