題目鏈結 p3384 【模板】輕重鏈剖分
樹剖模板題。
樹剖碼量真大(
樹剖主要是把樹形結構處理成鏈式結構,從而可以用諸如線段樹、樹狀陣列的資料結構進行維護。
學習樹剖之前得先會線段樹、了解lca以及樹型結構的一些專有名詞:樹鏈剖分專有名詞**講解
1.首先是乙個dfs函式,處理出結點的父親、重兒子、深度、子樹重量。非常簡單:
void
dfs1
(long
long now,
long
long fa,
long
long dep)
}
2.然後是另乙個dfs函式,用於處理每個結點的dfs序和重鏈。
void
dfs2
(long
long now,
long
long tp)
建線段樹的時候,我們是用每個節點的dfs序作為結點編號的(而不是結點原始編號),因為經過兩邊處理之後,有如下性質:
有了上面兩條性質,我們才能用資料結構進行維護。
下面是**參考資料的一段話
回顧上文的那個題目,修改和查詢操作原理是類似的,以查詢操作為例,其實就是個lca,不過這裡使用了top來進行加速,因為top可以直接跳轉到該重鏈的起始結點,輕鏈沒有起始結點之說,他們的top就是自己。需要注意的是,每次迴圈只能跳一次,並且讓結點深的那個來跳到top的位置,避免兩個一起跳從而擦肩而過。兩個性質:
如果u ,v
u,vu,
v是一條輕邊,那麼有siz
e[u]
>=2
∗siz
e[v]
size[u]>=2*size[v]
size[u
]>=2
∗siz
e[v]
。這個性質很顯然,輕邊的話說明v
vv是u
uu的輕兒子,又因為有siz
e重
>=s
ize輕
size重》=size輕
size
重》=s
ize輕
,因此有此性質。
從根結點到任意結點的路所經過的輕重鏈的個數必定都小於logn。不會證明,此性質可以證明樹剖的時間複雜度為o(n
logn
logn
)o(nlognlogn)
o(nlog
nlog
n) 。
ac**:
long
long n, m, r, q;
long
long aa[
100010];
struct node
e[200010];
long
long depth[
100010];
long
long top[
100010];
long
long father[
100010];
long
long size[
100010];
long
long dfsrank[
100010];
long
long son[
100010];
long
long ww[
100010];
long
long cnt;
long
long ct =1;
long
long head[
100010];
void
add(
long
long u,
long
long v)
void
dfs1
(long
long now,
long
long fa,
long
long dep)
//處理出結點的父親、重兒子、深度、子樹重量
}void
dfs2
(long
long now,
long
long tp)
//處理出重鏈以及各結點的dfs序
//線段樹模板----------------
struct node2
tr[400010];
void
pushup
(long
long k)
void
build
(long
long k,
long
long l,
long
long r)
long
long mid = l + r >>1;
build
(k *
2, l, mid)
;build
(k *2+
1, mid +
1, r)
;pushup
(k);
}void
pushdown
(long
long k)
}void
change
(long
long k,
long
long l,
long
long r,
long
long w)
pushdown
(k);
long
long mid =
(tr[k]
.l + tr[k]
.r)>>1;
if(r <= mid)
change
(k *
2, l, r, w)
;else
if(l > mid)
change
(k *2+
1, l, r, w)
;else
pushup
(k);
}long
long
query
(long
long k,
long
long l,
long
long r)
//線段樹模板------------
intmain()
dfs1
(r,0,1
);dfs2
(r, r)
;build(1
,1, n)
;for
(long
long i =
1; i <= m; i++
)else
}//直到兩個點在同一條鏈上,修改這兩個點之間的子鏈
if(depth[x]
> depth[y]
)swap
(x, y)
;change(1
, dfsrank[x]
, dfsrank[y]
, z);}
else
if(opt ==2)
else}if
(depth[x]
> depth[y]
)swap
(x, y)
; ans =
(ans +
query(1
, dfsrank[x]
, dfsrank[y]))
% q;
printf
("%lld\n"
, ans);}
else
if(opt ==3)
else
if(opt ==4)
}return0;
}
洛谷 P3384 模板 輕重鏈剖分(樹鏈剖分)
簡單點說,就是把一棵樹變成多條鏈。這裡說的是重鏈剖分。在遍歷一顆樹的時候,我們強制從父親節點走向兒子時,先走所有兒子中以兒子為根的子樹最大的那個兒子。其他的兒子不管什麼順序都可。這樣就可以把dfs序作為鏈。例如上面這棵樹,邊上的藍色數字就是遍歷順序。說一些定義 重邊 父親結點和重兒子連成的邊 輕邊 ...
P3384 輕重鏈剖分(樹剖模板)
如題,已知一棵包含 nn 個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作 11 格式 1 x y z1xyz 表示將樹從 xx 到 yy 結點最短路徑上所有節點的值都加上 zz。操作 22 格式 2 x y2xy 表示求樹從 xx 到 yy 結點最短路徑上所有節點的值之和。操...
P3384 模板 輕重鏈剖分(樹鏈剖分模板)
入口 題目描述 如題,已知一棵包含 nn 個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作 11 格式 1 x y z1 x y z 表示將樹從 xx 到 yy 結點最短路徑上所有節點的值都加上 zz。操作 22 格式 2 x y2 x y 表示求樹從 xx 到 yy 結點最短...