虛樹學習筆記

2022-01-10 15:02:13 字數 2013 閱讀 1163

虛樹常常被使用在樹形 \(dp\)中。

有些時候,我們需要計算的節點僅僅是一棵樹中的某幾個節點

這個時候如果對整棵樹都進行一次計算開銷太大了

所以我們需要把這些節點從原樹中抽象出來

按照它們在原樹中的關係重新建一棵樹,這樣的樹就是虛樹

在構建之前,我們需要把所有需要加入的節點按照 \(dfn\) 序從小到大排好序

在加點時,我們要用棧維護乙個最右鏈

在這個鏈左邊的虛樹都已經構建完成

我們設 \(top\) 為棧頂,設要加入的節點為 \(now\),設棧頂元素與 \(now\) 的 \(lca\) 為 \(lc\)

在加入的時候,會有以下幾種情況

此時我們直接把 \(now\) 接在最右鏈之後即可

\(2\)、\(lc\) 位於 \(sta[top]\) 和 \(sta[top-1]\)之間

此時 \(sta[tp]\) 已經不在最右鏈上,將其在虛樹上和 \(lc\) 連邊後出棧

同時把 \(lc\) 和 \(now\) 依次入棧

\(3\)、\(lc\) 為 \(sta[top-1]\)

和上面幾乎一樣,只是不把 \(lc\) 入棧

\(4\)、\(lc\) 的深度比 \(sta[top-1]\) 還小

我們把 \(sta[top]\) 和 \(sta[top-1]\) 連邊後出棧,重複之前的操作

這樣,我們直接在建出來的虛樹上 \(dp\) 就可以了

設總點數為 \(k\),則時間複雜度為 \(o(klogk)\)

以p2495 [sdoi2011]消耗戰為例

#include#include#include#include#define rg register

inline int read()

while(ch>='0' && ch<='9')

return x*fh;

}const int maxn=1e6+5;

int h[maxn],tot=1,h2[maxn],t2=1;

struct asdb[maxn],b2[maxn];

void ad(rg int aa,rg int bb,rg int cc)

void ad2(rg int aa,rg int bb)

int n,m,fa[maxn],dep[maxn],son[maxn],siz[maxn];

long long mindis[maxn];

void dfs1(rg int now,rg int lat)

}int dfn[maxn],dfnc,tp[maxn],stk[maxn],cnt,sta[maxn],js;

void dfs2(rg int now,rg int top)

}bool cmp(rg int aa,rg int bb) else

}break;

} else

} sta[++js]=now;

}bool vis[maxn];

long long dfs(rg int now,rg int lat)

if(vis[now]) else

vis[now]=0;

h2[now]=-1;

return cs;

}int main()

printf("%lld\n",dfs(1,0));

} return 0;

}

虛樹學習筆記

將關鍵點按dfs序排序後,所有關鍵點與相鄰關鍵點的lca合起來構成虛樹 通常還要加上整棵樹的根 虛樹至多有2k2k 個點。體現在實現中就是每次都pop若干點,並有機會push2個點。stk中存的是從根到當前點的遞迴棧中目前選入虛樹的點。stk中的點之間都未連邊 因為事實上關係還未確定 pop掉乙個點...

虛樹 學習筆記

水平不夠,學習來湊 又開了個天大的新坑 sdoi 2011 消耗戰 題目大意就是講 給出一棵樹,有邊權,然後給出k個查詢點,問從1號店不能到任何乙個查詢點的代價是多少.先考慮一下樹形動歸.dp i 表示從1不能到以i為根的子樹中的所有查詢點的最小代價 考慮維護乙個量,mins i 表示從1到i路徑最...

學習筆記 虛樹

模板 樹剖 lca 建虛樹 include using namespace std const int maxn 100000 10 int n,m,dp maxn vis maxn h maxn sta maxn top int fir maxn head maxn to maxn 1 nxt m...