樹鏈剖分真是難寫極了:你需要先熟練掌握深搜、線段樹、倍增。。。(都是不好寫的東西啊,一手滑就wa)
一、簡介
樹鏈剖分通常用於維護靜態樹上路徑資訊的問題。樹鏈剖分的核心就是將數分為若干重鏈、輕鏈,然後把他們當做序列,按順序拼接起來,處理序列上的區間問題
二、相關量
fa【x】:x
在樹中的父親(用於倍增)
dep【x】:
x在樹中的深度(用於倍增)
size【x】:
x的子樹節點數(用於線段樹操作)
son【x】:
x的重兒子,
u --> son【u
】為重邊(用於建重邊)
top【x】:
x所在重路徑的頂部節點(深度最小)(用於倍增)
id【x】:x
nw【id【x
】】:線段樹中第id【
x】個位置對應樹中節點編號,即nw【
id【x】】
= x(用於查詢回答等各種操作)
三、流程
第一遍dfs處理出fa,
dep,
size
,son
第二遍dfs處理出
top,id,
nw(先處理重邊再處理輕邊)
int dep[maxn * 4],fa[maxn * 4],siz[maxn * 4],son[maxn * 4];void dfs1(int x,int f,int
deep)
}}int id[maxn * 4],idx,top[maxn * 4],nw[maxn * 4
];void dfs2(int x,int
topf)
}
拆分成若干重路徑倍增處理成若干個線段樹上區間操作
int qrange(int ll,intrr)
if(dep[ll] >dep[rr])swap(ll,rr);
ans = 0
; query(
1,n,id[ll],id[rr],1
); anss +=ans;
anss %=mod;
return
anss;
}void addrange(int ll,int rr,int
x)
if(dep[ll] >dep[rr])swap(ll,rr);
addchange(
1,n,id[ll],id[rr],x,1);}
int qson(int
ro)void addson(int ro,int
x)
線段樹操作
structnode
tr[maxn * 8];int
ans;
void pushdown(int ro,int
len)
void build(int ll,int rr,int
ro)
else
}void query(int ll,int rr,int al,int ar,int
ro)
else
}
四、複雜度
o(log^2n)
五、題洛谷3384【模板】樹鏈剖分
1 #include2 #include3using
namespace
std;
4#define maxn 200005
5int
n,m,r,mod;
6int to[maxn * 4],head[maxn * 4],nxt[maxn * 4
],cnt;
7int
a[maxn];
8void add(int u,intv)9
14int dep[maxn * 4],fa[maxn * 4],siz[maxn * 4],son[maxn * 4
];15
void dfs1(int x,int f,int
deep)
1632}33
}34int id[maxn * 4],idx,top[maxn * 4],nw[maxn * 4
];35
void dfs2(int x,int
topf)
3648}49
struct
node
50 tr[maxn * 8
];53
intans;
54void pushdown(int ro,int
len)
5564
void build(int ll,int rr,int
ro)65
72else
7380}81
void query(int ll,int rr,int al,int ar,int
ro)82
89else
909697}
98void addchange(int ll,int rr,int al,int ar,int x,int
ro)99
106else
107115
116}
117int qrange(int ll,int
rr)118
129if(dep[ll] >dep[rr])swap(ll,rr);
130 ans = 0
;131 query(1,n,id[ll],id[rr],1
);132 anss +=ans;
133 anss %=mod;
134return
anss;
135}
136void addrange(int ll,int rr,int
x)137
145if(dep[ll] >dep[rr])swap(ll,rr);
146 addchange(1,n,id[ll],id[rr],x,1
);147
}148
int qson(int
ro)149
154void addson(int ro,int
x)155
158int
main()
159169 dfs1(r,0,1
);170
dfs2(r,r);
171 build(1,n,1
);172
for(int i = 1; i <= m; i ++)
173182
else
if(k == 2)//
求x到y的最短路徑上所有節點之和
183188
else
if(k == 3)//
以x為根節點的子樹所有節點加z
189194
else
if(k == 4)//
求以x為根節點的子樹所有節點值之和
195200
}201
return0;
202 }
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...
演算法入門 樹鏈剖分 輕重鏈剖分
目錄 3.0 求 lca 4.0 利用資料結構維護資訊 5.0 例題 參考資料 資料結構入門 線段樹 發表於 2019 11 28 20 39 dfkuaid 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...
樹鏈剖分 樹剖換根
這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...