bzoj 4390(樹上差分)

2022-07-13 10:03:10 字數 1834 閱讀 4827

給你一顆有n

n個結點的樹以及m

m個路徑。對於每乙個路徑pat

hipa

thi​

,代表著你將會從uiu

i​走到vivi

​。現在問你,你走完著m

m個路徑後,在這n

n個結點中經過的最多的次數。

首先,如果我們用dfs

dfs在樹上暴力去跑的話,顯然時間肯定是接受不了的。因此我們需要考慮一種較為優美的演算法。

我們發現,經過每乙個路徑pat

hipa

thi​

,本質上是使路徑pat

hipa

thi​

上的所有的點權+1+

1,如果這個問題是在序列上的話,我們直接就可以用線段樹或差分樹狀陣列去做。而正因為這個問題是在樹上進行的,因此為了簡化問題,我們則需要將樹形的結構轉化成鏈式結構。

因此根據轉化的不同,該問題可以通過樹鏈剖分或者樹上差分去解決。

而顯然樹上差分相對來說比較簡單。

我們只需要令cnt

[ui]

+1cn

t[ui

​]+1

,cnt[

vi]+

1cnt

[vi​

]+1,並且令cnt

[lca

[ui,

vi]]

−1cn

t[lc

a[ui

​,vi

​]]−

1,cnt

[fa[

lca[

ui,v

i]]]

−1cn

t[fa

[lca

[ui​

,vi​

]]]−

1即可。如果我們採用上述差分方法,在最後我們進行dfs

dfs回溯的時候,當前結點u

u就能夠獲得他的兒子們的權值。

整體的時間複雜度:o(n

logn

)o(n

logn

)

#include

using

namespace std;

const

int maxn=

500005

;const

int log=20;

struct nodeq[maxn<<1]

;int head[maxn]

,cnt=0;

void

add_edge

(int from,

int to)

struct lca

}void

init

(int root,

int n)}}

void

swim

(int

&x,int h)

}int

query

(int x,

int y)

}return anc[x][0

];}}lca;

int bit[maxn]

;void

search

(int x,

int fa)

}int

main()

lca.

init(1

,n);

while

(m--

)search(1

,-1)

;int maxx=0;

for(

int i=

1;i<=n;i++

)printf

("%d\n"

,maxx)

;return0;

}

bzoj 3631 (樹上差分)

給你一棵有n n個結點的樹,現在給你乙個大小為n n的排列,說明你的行走路徑。你每經過樹上的每乙個點,你就需要將這個點的點權加1。問你最後所有點的點權大小。根據題目的意思,很明顯這道題是乙個非常典型的點差分的問題。我們只需要對結點uiu i vi vi 以及lca ui,vi l ca u i v ...

樹上差分的整理(點的樹上差分和邊的樹上差分)

點的樹上差分 若經過 u 到 v 的所有點,tmp u tmp v tmp lca u,v tmp parent lca u,v 0 例題 include using namespace std struct ss ss data 600010 int n,q int a 300010 head 6...

BZOJ2588 主席樹 樹上差分

這種類似於第k小的題,一般容易想到主席樹,但是樹鏈並不能不是乙個按順序的序列,使用樹鏈剖分也不太容易維護幾條鏈之間的第k小關係。但是可以從主席樹的字首和思想入手,一般情況的主席樹,查詢的時候是query r query l 1 來詢問區間內的數值數量,在這一題裡面,可以考慮到樹上差分,從樹根開始,以...