2020.5.6
題目描述我就不寫了,模板題。
之前寫過倍增+tarjan求lca的板子,但是倍增這東西我貌似還沒太搞懂,只寫過st表,可能是我太菜了嗚嗚嗚。
樹剖其實我之前也沒太弄懂,後來做了一道河南某年的省選題就豁然開朗了(但還沒ac,可能是我用的線段樹板子出問題了)。就是用2遍dfs處理好樹內邊的歸屬關係 + 不斷向上溯祖,追溯到同乙個祖先即是答案。top陣列存放子樹頂節點編號,depth存放節點所處的層數,fa陣列是存節點的上乙個節點,son是重兒子,言外之意就是子樹中size最大的乙個子書根節點,然後size就是用來存子樹底下的節點數量。
這是lca,不過感覺樹剖和線段樹經常是配合使用的,因為一般都是要區間更新,所以乙個乙個查o(n)太慢了,需要先dfs序重新編號,然後建立線段樹,用乙個id陣列記錄編號,線段樹就能直接更新了,感覺還是很神奇的演算法。
**如下,前向星記得陣列開大,這題真**,我開了40w還是不夠,後來100w就ac了,毒瘤。
#include
using
namespace std;
#define limit (1000 + 5)
//防止溢位
#define inf 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)
//一步兩步
#define eps 1e-6
#define fastio ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%lld\n",a );
#define pi(a,b) pair
#define rep(i, a, b) for(int i = a ; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define mod 998244353
#define fopen freopen("c:\\users\\administrator01\\clionprojects\\untitled24\\data.txt", "rt", stdin)
typedef
long
long ll;
typedef
unsigned
long
long ull;
ll read()
while
(s >=
'0'&& s <=
'9')
return x * sign;
}//快讀
void
write
(ll x)
int n, k,cnt;
int head[limit]
,depth[limit]
,fa[limit]
,top[limit]
,sizes[limit]
,son[limit]
;struct nodeedge[limit<<2]
;void
init()
void
add(
int u,
int v)
void
dfs(
int u,
int pre)}}
void
dfs2
(int u,
int topp)
for(
int i = head[u]
;~i; i = edge[i]
.next)}}
intquery
(int x,
int y)
return depth[x]
< depth[y]
? x : y;
}int
main()
dfs(root,0)
;dfs2
(root, root)
;rep
(i ,
1, k)
return0;
}
樹鏈剖分 洛谷 P3384 模板 樹鏈剖分
step1 problem 題目 給你一棵n個點樹,m個操作,r是根,結果取模mod.操作1 格式 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z 操作2 格式 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和 操作3 格式 3 x z 表示將以x為根節點的子樹內所有節...
樹鏈剖分 洛谷P3384樹剖模板
如題,已知一棵包含n個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作1 格式 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z 操作2 格式 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和 操作3 格式 3 x z 表示將以x為根節點的子樹內所有節...
樹鏈剖分求LCA
這裡先推薦兩道練習的裸題 首先是求點 codevs4605 lca 就是求兩個點的公共祖先,每次詢問xor上上乙個詢問的答案。先是兩遍dfs dfs1 把dep siz son求出來 dfs2 求出top和w siz v 表示以v為根的子樹的節點數 dep v 表示v的深度 根深度為1 top v ...