樹鏈剖分詳解及模板

2021-07-22 03:17:31 字數 1914 閱讀 8767

這幾天學習了一下樹鏈剖分,順便寫一下我的理解、

早上看了一下別人的講解,雲裡霧裡,終於算是搞懂了、

重邊:某個節點x到孩子節點形成的子樹中節點數最多的點child之間的邊,由定義發現除了葉子節點其他節點只有一條重邊

重邊是可以放在一塊兒更新的,而有

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

所以這樣查詢的時間複雜度相當於log2(n)

其實樹鏈剖分就是把邊雜湊到線段樹上的資料結構。

實現的話很簡單,用兩個dfs處理數數的資訊,重邊以及輕邊,然後就是一些線段樹的操作了。

模板「:以spoj 375 為例

#include 

#include

#include

#include

using

namespace

std;

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

const

int n = 10005;

int dep[n],siz[n],fa[n],id[n],son[n],val[n],top[n]; //top 最近的重鏈父節點

int num;

vector

v[n];

struct tree

};tree e[n];

void dfs1(int u, int f, int d)

}void dfs2(int u, int tp)

}#define lson(x) ((x<<1))

#define rson(x) ((x<<1)+1)

struct tree

;tree tree[4*n];

void pushup(int x)

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

int mid=(l+r)>>1;

build(l,mid,v*2);

build(mid+1,r,v*2+1);

pushup(v);

}void update(int o,int v,int val) //log(n)

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

if(v<=mid)

update(o*2,v,val);

else

update(o*2+1,v,val);

pushup(o);

}int query(int x,int l, int r)

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

int ans = 0;

if (l <= mid) ans = max(ans, query(lson(x),l,r));

if (r > mid) ans = max(ans, query(rson(x),l,r));

return ans;

}int yougth(int u, int v)

ans = max(query(1,id[tp1], id[u]), ans);

u = fa[tp1];

tp1 = top[u];

}if (u == v) return ans;

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

ans = max(query(1,id[son[u]], id[v]), ans);

return ans;

}void clear(int n)

int main()

build(1,num,1);

char s[200];

while(~scanf("%s",&s) && s[0]!='d')

clear(n);

}return

0;}

樹鏈剖分詳解及模板

這幾天學習了一下樹鏈剖分,順便寫一下我的理解 早上看了一下別人的講解,雲裡霧裡,終於算是搞懂了 樹鏈剖分是解決在樹上進行插點問線,插線問點等一系列樹上的問題 假如現在給你一棵樹,然後沒兩條邊之間有一條權值,有一些操作,1 x y之間的最大權值是多少,2 改變x y之間的權值 那麼就要想想辦法了,我們...

樹鏈剖分 模板

class match node a n struct no no aa n 4 void init void addpage int x,int y void dfs int s,int faa,int h 根節點,父節點和深度的 if max 0 son s sign void dfs2 int...

模板 樹鏈剖分

define maxn 50010 define l u u 1 define r u u 1 1 寫在類裡面爆棧 int n,m,q int tim 時間戳 int num maxn 樹上每個節點的初始值 int siz maxn siz u 表示以u為根的子樹的節點數 int top maxn ...