1. 程式人生 > >Noip前的大抱佛腳----資料結構

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七彩樹離線版/[湖南集訓]談笑風生)