虛樹學習筆記

2022-05-11 13:16:05 字數 1543 閱讀 6218

題面傳送門

虛樹,顧名思義是虛的,就是不能完全代表一棵樹的樹。

換句話說,虛樹上只保留對我們有用的節點。而其它節點就沒有必要存在。

可以來看一道例題[sdoi2011]消耗戰

我們很容易發現,如果只保留樹上的資源點和資源點兩兩之間的lca,那麼其餘的點全部是沒有用的。

同時我們又知道結論:\(n\)個點兩兩的\(lca\)只有最多\(n-1\)個點。

所以這樣子建出來的虛樹一定是可以的。

說的好聽,這怎麼建啊

我們先將所有資源點按dfs序公升序排序,然後依次插入樹中。

具體的,維護乙個dfs序公升序的棧,這個棧表示虛樹最右邊的一條鏈。因為我插入的點dfs序遞增,我只需要知道最右邊的資訊即可。

然後設棧頂為\(top\),棧頂的下面乙個是\(y\),待插入的點為\(x\),\(lcas=lca(top,x)\)那麼有分類討論:

如果\(d[lca],即我不接著這條鏈走,我要換一條鏈走,所以不斷彈出棧與連邊直至這個條件不滿足。

然後這時又有情況:

如果此時的\(lca=top\),那麼什麼都不用做。

如果不等於,那麼\(d_top\)一定小於\(d_lca\),而這時又是換一邊走,所以把連邊然後\(top\)彈出然後看看\(lcas\)是否為\(y\)然後看是否加入即可。

最後把\(x\)加入,別忘了最後把棧中的邊加入虛樹。

最後樹形\(dp\)即可。

時間複雜度\(o(mlogn+\sum\limitslogn)\)

code:

#include#define ll long long

#include#define beg(x) int cur=s.h[x]

#define end cur

#define go cur=tmp.z

#define min(a,b) ((a)<(b)?(a):(b))

using namespace std;

int n,m,k,x,y,z,st[250039],now,lcas,pus,sh,dh,flag[250039],a[250039],d[250039],top[250039],siz[250039],son[250039],fa[250039],dfn[250039];

ll w[250039],dp[250039];

struct yyy;

struct ljb;h[x]=head;}

}s,g;

inline void dfs1(int x,int last)

inline void dfs2(int x,int last)

inline int lca(int x,int y)

inline bool cmp(int x,int y)

inline void dfs(int x)

int main()

while(--sh)g.add(st[sh],st[sh+1],0);dfs(1);

printf("%lld\n",dp[1]); for(j=1;j<=k;j++) flag[a[j]]=0;

}}

虛樹學習筆記

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

虛樹 學習筆記

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

虛樹學習筆記

虛樹常常被使用在樹形 dp 中。有些時候,我們需要計算的節點僅僅是一棵樹中的某幾個節點 這個時候如果對整棵樹都進行一次計算開銷太大了 所以我們需要把這些節點從原樹中抽象出來 按照它們在原樹中的關係重新建一棵樹,這樣的樹就是虛樹 在構建之前,我們需要把所有需要加入的節點按照 dfn 序從小到大排好序 ...