樹鏈剖分 樹上倍增 線段樹 遙遠的國度

2021-09-25 19:31:26 字數 2390 閱讀 9367

難點在於如何處理換根操作。我們可以分情況討論。假設當前根節點為roo

troot

root

,詢問子樹為son

。son。

son。

然後就是比較模板的樹鏈剖分了。

#include

#define int long long

using

namespace std;

const

int n =

200000

;int n, m, tot =0;

int dfn[n]

, l[n]

, r[n]

, dep[n]

;int f[n][25

], size[n]

, son[n]

, top[n]

, val[n]

;vector <

int> g[n]

;struct seg a[n*10]

;void

dfs1

(int x,

int fa)

return;}

void

dfs2

(int x,

int cur)

r[x]

= tot;

return;}

voiddp(

void

)void

build

(int p,

int l,

int r)

int mid = l+r >>1;

build

(p*2

,l,mid)

;build

(p*2+1

,mid+

1,r)

; a[p]

.min =

min(a[p*2]

.min,a[p*2+

1].min)

;return;}

void

spread

(int p)

void

change

(int p,

int l,

int r,

int v)

spread

(p);

int mid = a[p]

.l+a[p]

.r >>1;

if(l <= mid)

change

(p*2

,l,r,v);if

(r > mid)

change

(p*2+1

,l,r,v)

; a[p]

.min =

min(a[p*2]

.min,a[p*2+

1].min)

;return;}

intask

(int p,

int l,

int r)

void

modify

(int x,

int y,

int v)

if(dep[x]

> dep[y]

) x ^

= y ^

= x ^

= y;

change(1

,l[x]

,l[y]

,v);

return;}

intgetfa

(int x,

int y)

signed

main

(void

)for

(int i=

1;i<=n;

++i)

scanf

("%lld"

, val+i)

;dfs1(1

,0),

dfs2(1

,1),

dp();

build(1

,1,n);

int root;

scanf

("%lld"

,&root)

;while

(m --)if

(opt ==3)

if(dep[root]

> dep[x]

&& x == f[ y =

getfa

(root,dep[root]

-dep[x]-1

)][0

])else

printf

("%lld\n"

,ask(1

,l[x]

,r[x]))

;}}return0;

}

BZOJ 3083 樹鏈剖分 倍增 線段樹

思路 先隨便選個點 鏈剖 線段樹 1操作 就直接改root變數的值 2操作 線段樹上改 3操作 分成三種情況 1.new root xx 整個子樹的min就是ans 2.lca new root,xx xx query 一下 當前的標號 和當前的標號 size 鏈剖不就是個特殊的dfs序嘛 3.lc...

樹上操作 樹鏈剖分 線段樹

有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。樹鏈剖分後,節點x及其子樹節點會在一段連續的區間內,用...

學習筆記 倍增 樹鏈剖分

給你一棵樹,包括它的邊和根節點,詢問2個節點的最近公共祖先 容易想到一種方法,先dfs一遍,然後對於詢問的2個節點,先跳到同一高度,然後一起往上跳 好像是logn的演算法呢,emmm卡成一條鏈怎麼辦,這就退化成nm了 倍增是什麼東東捏,就是在往上跳的過程中不是一次跳一格,而是跳2 k次方 就算是一條...