目錄後記
**【模板】輕重鏈剖分
傳送門總的來說,就是乙個不難理解,碼量**的東西
推幾篇題解,講得不錯
線段樹(必備),倍增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 ...