虛樹學習筆記(洛谷2495 消耗戰)

2021-09-02 00:21:39 字數 3361 閱讀 2070

題目鏈結

因為辣雞csdn,導致之前快寫好的部落格沒了

qwq悲傷逆流成河qwqqq

首先虛樹,這個東西,我感覺是一種思想,或者是方法,而並不是乙個資料結構什麼的。

他主要是用來解決:給出一棵樹,每次詢問選擇一些關鍵點,求一些資訊。

這些資訊的特點是,許多未選擇的點可以通過某種方式剔除而不影響最終結果。

於是就有了建虛樹這個演算法。我們根據原樹的資訊重新建樹,這棵樹中要盡量少地包含非關鍵節點。 這棵樹就叫做虛樹。這棵虛樹包含任意兩個關鍵節點的lca。

通常這類題o(n

m)

o(nm)

o(nm)會t

tt飛,而o(∑

詢問點個

數)

o(\sum 詢問點個數)

o(∑詢問點

個數)是能跑得過的qwq

那我們應該怎麼構造虛樹呢qwq我們把所有關鍵點按照dfs序排好序。

然後,虛樹要有乙個根。這裡一般直接把1號節點設為根。構建虛樹的主要過程就是使用乙個棧,維護從根開始的一條鏈。這條鏈上的所有點的dfs序一定是遞增的。

我們把關鍵點掃瞄一遍,一邊維護這個棧一邊連邊構建虛樹。

具體來說:

1.把根節點放入棧中2.把所有關鍵點點掃一遍。設當前的節點為x

xx,棧頂(鏈末端)的節點為y

yy。求出x

xx和y

yy的lca

lcalc

a。此時有2種情況。

1)lc

alca

lca為y

yy。此時x

xx在y

yy子樹內。我們就把x

xx壓入棧,相當於直接把x

xx新增到這條鏈的末尾。

2)x ,y

x,yx,

y分立在lca

lcalc

a的兩個子樹中。此時y這個子樹中的所有關鍵點一定都被遍歷過了。(原因:設有一關鍵點a在y子樹中,沒有被遍歷過。則dfn

[y

]

n[a]

n[x]

dfn[y]df

n[y]

n[a]

n[x]

。但是我們是把關鍵點按照dfs序來排的,a一定在x之前被掃)

因此y子樹內的所有關鍵點都已經被被加入虛樹。接下來我們要把y

−>lc

ay->lca

y−>lc

a這一段的點加入虛樹。我們設棧頂的節點為y

yy,棧頂的第二個節點為zzz。

重複以下操作:

1.若dfn

[z

]>df

n[lc

a]

dfn[z]>dfn[lca]

dfn[z]

>df

n[lc

a]直接連邊z

−>

yz->y

z−>

y,然後把y

yy出棧。

2.若dfn

[z]=

dfn[

lca]

dfn[z]=dfn[lca]

dfn[z]

=dfn

[lca

]這意味著z

zz就是lca

lcalc

a。直接連邊lca

−>

ylca->y

lca−

>

y。此時子樹已構建完畢。

3.若dfn

[z

]>df

n[lc

a]

dfn[z]>dfn[lca]

dfn[z]

>df

n[lc

a],說明lca

lcalc

a被yy

y和zz

z夾在中間。此時我們必須要把lca

lcalc

a加入虛樹,所以連邊lca

−>

ylca->y

lca−

>

y,然後把y

yy彈出棧,把lca入棧。然後子樹構造完畢。

最後把棧裡面的元素搞一搞,每次add

edge

(s[t

op−1

],s[

top]

)addedge(s[top-1],s[top])

addedg

e(s[

top−

1],s

[top

])即可感覺配合**會比較好理解

void

solve()

else

else}}

}if(sta[top]

!=a[i]

) sta[

++top]

=a[i];}

while

(top>1)

}

那麼剩下的主要就是dpdp

dp部分了首先,我們定義mn[

x]

mn[x]

mn[x

]表示在原樹上1到x

1到x1到

x的路徑上邊權的最小值,f[x

]f[x]

f[x]

表示切割完x

xx子樹內所有關鍵點的最小花費。

對於當前點x

xx,如果他是關鍵點,那麼必須切割這個點到1的路經上的一條邊,那麼就是mn[

x]

mn[x]

mn[x

],否則f[x

]=mi

n(mn

[x],

∑f[s

on

]f[x]=min(mn[x],\sum f[son]

f[x]=m

in(m

n[x]

,∑f[

son]

上**

intdp(

int x,

int flag)

if(tag[x]

==flag)

return

min(sum,mn[x]);

}

其中有乙個要注意的地方就是虛樹的時候,因為每次要重新建樹,所以要清空poi

nt

point

poin

t陣列,而由於時間原因,又不能直接mem

se

tmemset

memset

,所以我們只能使用奇妙的手段!自殺式遍歷通過取位址,不斷修改poi

nt

point

poin

t

for

(int

&i=point[x]

;i;i=nxt[i]

)

由於宕機了三次qwq

所以暫時沒有辦法放整個題的**

虛樹 P2495 SDOI2011 消耗戰

好久沒有學習新的知識了。今天我學習了一下虛樹。虛樹就是乙個不存在的樹。用來簡化問題。它只包括一些關鍵點和他的lca 我們來看看上面這一道題 給出一棵樹,含有邊權。每次詢問給出k個點,然後詢問每個點與根斷開的最小代價。因為資料的關係肯定沒法直接dp過去的。首先我們可以發現可以與根到其他點的路徑沒有關係...

P2495 SDOI2011 消耗戰 虛樹

這是我做的第一道虛樹題啊,趕腳不錯.其實虛樹也沒什麼奇怪的,就是每棵樹給你一些點,讓你多次查詢,但是我不想每次都o n 所以我們每次針對給的點建一棵虛樹,只包含這些點和lca,然後在這棵虛樹上進行樹形dp,維護每個點的最小連邊權值,這樣的複雜度就會降低不少.這裡我寫了兩種寫法 其實都是抄的 一種是正...

P2495 SDOI2011 消耗戰 虛樹

題意 一棵樹上給定點集,求到根的最小割。每次詢問只和給定的點集以及它們的lca有關係,那麼把這些點拿出來建立一棵樹。再進行樹dp。具體操作把所有詢問點按照dfn排序,再用乙個棧進行維護建樹。彈棧的時候並不是每個點都和棧中第二個元素連邊,有可能最後乙個彈棧點和新的lca連邊。dp轉移時需要查詢樹鏈的最...