樹鏈剖分 學習整理

2021-07-28 20:36:36 字數 3234 閱讀 3866

「在一棵樹上進行路徑的修改、求極值、求和」乍一看只要線段樹就能輕鬆解決,實際上,僅憑線段樹是不能搞定它的。我們需要用到一種貌似高階的複雜演算法——樹鏈剖分。

樹鏈,就是樹上的路徑。剖分,就是把路徑分類為重鏈和輕鏈。

重兒子:siz[u]為v的子節點中siz值最大的,那麼u就是v的重兒子。

輕兒子:v的其它子節點。

重邊:點v與其重兒子的連邊。

輕邊:點v與其輕兒子的連邊。

重鏈:由重邊連成的路徑。

輕鏈:輕邊。

剖分後的樹有如下性質:

性質1:如果(v,u)為輕邊,則siz[u] * 2 < siz[v];

性質2:從根到某一點的路徑上輕鏈、重鏈的個數都不大於logn。

例題 : spoj 375 的**

1 #include2 #include3 #include4

using

namespace

std;

5int

n,m;

6struct

node tree[100010*4];9

void built(int l,int r,int

k)10

13int mid=(l+r)/2

;14 built(l,mid,k*2);built(mid+1,r,k*2+1

);15 tree[k].sum=tree[k*2].sum+tree[k*2+1

].sum;16}

17void change(int k,int pos,int

x)18

21int mid=(l+r)/2;22

if(pos<=mid) change(k*2

,pos,x);

23if(pos>mid) change(k*2+1

,pos,x);

24 tree[k].sum=tree[k*2].sum+tree[k*2+1

].sum;25}

26int query(int k,int l,int r)//

區間查詢(以求和為例)

2730

int mid=(tree[k].l+tree[k].r)/2;31

if(l<=mid) ans+=query(k*2

,l,min(mid,r));

32if(r>mid) ans+=query(k*2+1,max(mid+1

,l),r);

33return

ans;34}

35int find(int k,int

pos)

3638

int mid=(tree[k].l+tree[k].r)/2;39

if(pos<=mid) find(k*2

,pos);

40if(pos>mid) find(k*2+1

,pos);41}

42void allchange(int k,int ls,int rs,int

x)43

46int mid=(l+r)/2;47

if(ls<=mid) allchange(k*2

,ls,min(rs,mid),x);

48if(rs>mid) allchange(k*2+1,max(ls,mid+1

),rs,x);

49}

50int main()//

線段樹 維護 區間求和 和 單點修改

51

未完成**存檔:

1 #include2 #include3 #include4

#define clr(a,b) memset(a,b,sizeof(a))

5using

namespace

std;

6const

int maxn=10010;7

struct

nodee[5005*4

];10

struct

tretree[maxn*4

];13

intn,pos[maxn],dep[maxn],head[maxn],m,t,p;

14int

fa[maxn],siz[maxn],son[maxn],top[maxn],nid;

15void add(int

from,int to,int

value)

19void

clear()25}

26void dfs_1(int s,int fu,int deepth)33}

34void gettop(int s,int f)42}

43void built(int l,int r,int k)

46int mid=(l+r)/2

;47 built(l,mid,k*2);built(mid+1,r,k*2+1

);48}49

void update(int k,int ps,int

val)

52int mid=(tree[k].l+tree[k].r)/2;53

if(ps<=mid) update(k*2

,ps,val);

54else update(k*2+1

,ps,val);

55 tree[k].value=max(tree[k*2].value,tree[k*2+1

].value);56}

57int query(int k,int l,int

r)58

66int find(int u,int

v)70 ans=max(ans,query(1

,pos[t1],pos[t2]));

71 u=fa[t1];t1=top[u];72}

73if(u==v) return

ans;

74if(dep[u]>dep[v]) swap(u,v);

75return max(ans,query(1,pos[u]+1

,pos[v]));76}

77int

main()78

90char s[15];int

u,v;

91while(scanf("

%s",s)==1)92

97}98return0;

99 }

備註:引用自網路

樹鏈剖分 學習整理

重兒子 siz u 為v的子節點中siz值最大的,那麼u就是v的重兒子。輕兒子 v的其它子節點。重邊 點v與其重兒子的連邊。輕邊 點v與其輕兒子的連邊。重鏈 由重邊連成的路徑。輕鏈 輕邊。剖分後的樹有如下性質 性質1 如果 v,u 為輕邊,則siz u 2 siz v 性質2 從根到某一點的路徑上輕...

樹鏈剖分演算法整理

樹鏈剖分可以把樹分成若干條鏈,從而維護樹上的路徑資訊。本質思想是把樹剖成可以用線性結構儲存的結構,然後可以資料結構維護。分為三種 重鏈剖分 長鏈剖分 實鏈剖分。以下以重鏈剖分為主。重鏈剖分可以將樹上的任意一條路徑劃分成不超過o l ogn o logn o logn 條連續的鏈,每條鏈上的點深度互不...

Query on a tree 樹鏈剖分整理

樹鏈剖分整理 樹鏈剖分就是把樹拆成一系列鏈,然後用資料結構對鏈進行維護。通常的剖分方法是輕重鏈剖分,所謂輕重鏈就是對於節點 u的所有子結點v,size v 最大的v與u 的邊是重邊,其它邊是輕邊,其中 size v 是以v 為根的子樹的節點個數,全部由重邊組成的路徑是重路徑,根據 上的證明,任意一點...