模板 輕重鏈剖分

2022-07-11 12:30:23 字數 3194 閱讀 7584

目錄後記

**【模板】輕重鏈剖分

傳送門總的來說,就是乙個不難理解,碼量**的東西

推幾篇題解,講得不錯

線段樹(必備),倍增lca(可以幫助理解,不會應該也可以),鏈式前向星(存圖,不會有人不會吧)

重兒子(子樹結點最多的兒子),重邊(某個點到它的重兒子連成的邊),重鏈(重邊連成的鏈),輕兒子(除重兒子外的其它兒子),輕邊,輕鏈

int n , m , rt , mod;//如題所述,為了習慣,p換位mod

int dat[nn];//輸入的初始值

int dep[nn] , fa[nn] , siz[nn] , hvyson[nn];

//dep[i]:i結點深度,fa[i]:父節點,siz[i]:以i為根的子樹大小,hvyson[i]:i結點的重兒子

int id[nn] , top[nn];

//id[i]:i結點的新標號,等下(第二輪dfs)會講,top[i]:i所在重鏈的頂端結點

我們需要處理出這些:

int dep[nn] , fa[nn] , siz[nn] , hvyson[nn];
void dfs1(int x , int fa_ , int deep) 

++siz[x];

}

我們需要處理出這些:

int id[nn] , top[nn];
void dfs2(int x , int chaintop) 

}

相信很多人都產生了疑問:為什麼要給結點按照dfs序重新編號,並優先處理重兒子呢?

由於是dfs序,那麼以任意乙個結點為根,整顆子樹的新編號都是連續的,這就是說,我們可以直接利用線段樹修改或查詢整顆子樹的權值,這就把3,4操作的時間複雜度降到了log級別

由於我們優先處理重兒子,所以同一條重鏈上所有結點的編號都是連續的,這也為線段樹操作提供了方便,以2操作為例(**解釋)

inline int path_query(int x , int y) 

if(dep[x] > dep[y])swap_(x , y);//此時x,y已經處於同一條重鏈上,強行讓y結點深度更大

res += query(root , id[x] , id[y]); //答案累加上x~y的點權

return res % mod;

}

修改操作同理:

inline int path_add(int x , int y , int z) 

if(dep[x] > dep[y])swap_(x , y);

change(root , id[x] , id[y] , z);

}

樹鏈剖分這個東西真的不難,就是很繁瑣,如果想學就真的要沉下心來好好寫**,不要急

#include #include #define nn 100010

#define ll long long

using namespace std;

int read()

int n , m , rt , mod;

int dat[nn];

int dep[nn] , fa[nn] , siz[nn] , hvyson[nn];

int id[nn] , top[nn];

//segmenttree-begin********************==

struct segmenttreetr[nn * 4];

int root;

int build(int l , int r)

return p;

}inline void spread(int p)

return;

}void change(int p , int l , int r , ll dat)

spread(p);

if(l > tr[p].r || r < tr[p].l)return;

change(tr[p].ls , l , r , dat);

change(tr[p].rs , l , r , dat);

tr[p].dat = (tr[tr[p].ls].dat + tr[tr[p].rs].dat) % mod;

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

//segmenttree-end********************====

//***********************************====

struct ednodeed[nn * 2];

int head[nn];

inline void addedge(int u , int v)

//***********************************====

void dfs1(int x , int fa_ , int deep)

++siz[x];

}void dfs2(int x , int linktop)

}//****************************************

inline void tree_add(int x , int z)

inline int tree_query(int x)

inline void swap_(int &a , int &b)

inline int path_add(int x , int y , int z)

if(dep[x] > dep[y])swap_(x , y);

change(root , id[x] , id[y] , z);

}inline int path_query(int x , int y)

if(dep[x] > dep[y])swap_(x , y);

res += query(root , id[x] , id[y]);

return res % mod;

}int main()

root = build(1 , n);

dfs1(rt , 0 , 0);

dfs2(rt , rt);

while(m--) }

return 0;

}

輕重鏈剖分

樹鏈剖分是一種將樹轉化為一條鏈的演算法,通常和線段樹,樹狀陣列,dp等針對鏈的演算法結合使用。正如題目所說,本文只講輕重鏈剖分 預處理首先扔出乙個定理 樹中任意一條路徑均可以拆分成一條鏈上 o log n 個連續區間。證明 構造 乙個dfs序就行了 但是實際 實現中,一般都是優先遍歷重兒子,這樣遍歷...

輕重鏈剖分

目錄樹剖完就是線段樹題了qwq 沒了題外話 鴿說叫 he y light decomposition 或 he y path decomposition 正確叫法 不是 這是真的 乙個節點子樹大小最大的兒子叫重兒子 節點到重兒子的邊叫重邊 一堆重邊叫重鏈 重兒子優先 dfs,於是重鏈連續,每條鏈可以...

樹鏈剖分(輕重樹)模板

例題 樹鏈剖分就是用兩個dfs重新給樹編號 深度 求父節點 求重兒子 子樹大小 每條重鏈的頂端,然後用線段樹維護新的編號的樹 include include using namespace std define n 200010 int n,m,r,mod int head n nex n e n ...