樹鏈剖分簡介(BZOJ1036)(洛谷2590)

2021-08-13 08:22:45 字數 2528 閱讀 3954

建議學樹剖的同學先學會dfs序,並有一定的資料結構基礎

樹鏈剖分,計算機術語,指一種對樹進行劃分的演算法,它先通過輕重邊剖分將樹分為多條鏈,保證每個點屬於且只屬於一條鏈,然後再通過資料結構(樹狀陣列、sbt、splay、線段樹等)來維護每一條鏈。

那它有什麼用呢?

它可以解決一些樹上路徑的一些問題。

一般的樹剖是輕重鏈剖分。當然還有更高階的長鏈剖分等。這裡先講輕重鏈剖分。

sz[x]:以x為根的子樹的節點個數

to[x]:x中節點最多的兒子編號(重兒子)

重邊:連線x與to[x]的邊

輕邊:除了重邊以外的邊

重鏈:由重邊構成的鏈

輕鏈:除了重邊以外的鏈

tp[x]:x所在的重鏈的起始點

剖分完後有一些性質:

輕邊(u,v),size(v)<=size(u)/2。 ž從根到某一點的路徑上,不超過o(logn)條輕邊,不超過o(logn)條重路徑。

容易發現樹剖是啟發式的。

實現輕重鏈剖分我們可以用兩遍dfs實現

第一遍dfs:求出每個節點的父親、深度、sz、to等。這個比較簡單。

void dfs1(int x,int depth)

}

第二遍dfs:優先遍歷重兒子。對於每乙個重兒子,繼承當前節點的重鏈。對於其它兒子,重新拉一條以自己為端點的重鏈。

void dfs2(int x)
仔細體會一下就可以發現,輕重鏈剖分其實就是優先遍歷重兒子的乙個dfs序。每一條重鏈/每乙個子樹都是連續的一段區間。

對於x到y的一條路徑,可以把它劃分為若干條重鏈(當然最後一條可能不完整)。

假設tp[x]>=tp[y]。

當tp[x]!=tp[y]時,對x到tp[x]這一段進行操作,然後把x賦成fa[tp[x]],重複上述操作。

當tp[x]=tp[y]時,對x到y這一段進行操作,結束操作。

下面給出偽**:

各種型別 函式名稱(int x,int y)

if (dep[x]id[y]到id[x])

}

以bzoj1036(洛谷p2590)為例:

這道題的操作有單點修改和詢問路徑最大值及路徑點權和,所以我們可以用線段樹維護。

**:

#include

#include

#include

#include

#define n 30005

using namespace std;

struct treet[n*4];

struct edgeed[n*2];

int n,m,k,nd,a[n],fa[n],dep[n],tp[n],to[n],h[n],sz[n],id[n],in[n];

inline int _read()

while (isdigit(ch)) num=(num<<3)+(num<<1)+(ch^48),ch=getchar();

return num*f;

}void addedge(int x,int y)

void dfs1(int x,int depth)

}void dfs2(int x)

void build(int l,int r,int x)

int mid=l+r>>1; build(l,mid,x*2),build(mid+1,r,x*2+1);

t[x].sum=t[x*2].sum+t[x*2+1].sum;

t[x].mx=max(t[x*2].mx,t[x*2+1].mx);

}void mdfy(int x,int p,int w)

int mid=t[x].l+t[x].r>>1;

if (p<=mid) mdfy(x*2,p,w);

else mdfy(x*2+1,p,w);

t[x].sum=t[x*2].sum+t[x*2+1].sum;

t[x].mx=max(t[x*2].mx,t[x*2+1].mx);

}tree find(int x,int l,int r)

tree srch(int x,int y)

if (dep[x]1,id[y],id[x]);

ans.mx=max(ans.mx,ret.mx);

ans.sum+=ret.sum; return ans;

}int main()

for (int i=1;i<=n;i++) a[i]=_read();

dfs1(1,1),tp[1]=1,dfs2(1),build(1,n,1);

m=_read(); char s[10]; int x,y;

while (m--)

}return

0;}

bzoj1036 樹的統計 樹鏈剖分 LCT

ac通道 題解 看到題目,發現是樹剖一眼題,所以就秒掉了。include include include include include include includeusing namespace std typedef long long ll define file read define m...

BZOJ 1036 樹的統計 樹鏈剖分模板

樹上n個點,支援單點修改,區間查詢最大值和sum和。此處只講大體思路,樹鏈剖分的詳細原理請移步op x top x top x 即該點的 dfs dfsdf s區間修改和區間查詢,就是先處理出兩點之間的樹鏈,由於樹鏈上的點的 dfs dfsdf s下面的 包括了區間修改和單點修改,以及區間查詢最大值...

BZOJ 1036 樹的統計 Count 樹鏈剖分

題目大意 一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到點v的路徑上的節點的權值和 ...