树链剖分多与线段树结合使用。
剖分后的树有如下性质:
性质1:如果
(
v
,
u
)
(v,u)
(v,u) 为轻边,则
s
i
z
e
[
u
]
∗
2
<
s
i
z
e
[
v
]
size[u] * 2 < size[v]
size[u]∗2<size[v]
性质2:从根到某一点的路径上轻链、重链的个数都不大于
log
2
n
\log_2n
log2n。
模板
void dfs1(int u, int FA, int depth)
{
dep[u] = depth;
fa[u] = FA;
size[u]++;
for (int k = head[u];k;k = map[k].next)
{
int v = map[k].to;
if (v == FA)
{
continue;
}
dfs1(v, u, depth+1);
size[u] += size[v];
if (size[v] > size[son[u]])
{
son[u] = v;
}
}
}
void dfs2(int u, int top)
{
Top[u] = top;
rk[u] = ++dfn;
id[dfn] = u;
if (son[u])
{
dfs2(son[u], top);
}
for (int k = head[u];k;k = map[k].next){
int v = map[k].to;
if (v != son[u] && v != fa[u])
{
dfs2(v, v);
}
}
endtree[u] = dfn;
}
int LCA(int x, int y)
{
while (Top[x] != Top[y])
{
if (dep[Top[x]] < dep[Top[y]])
{
swap(x, y);
}
x = fa[Top[x]];
}
if (dep[x] < fep[y])
{
swap(x, y);
}
return y;
}
树剖 + LCT
#include <stdio.h>
#include <iostream>
using namespace std;
#define MAXN 400000
#define LL long long
LL p, cnt, dfn, r;
int head[MAXN];
int size[MAXN], son[MAXN], fa[MAXN], Top[MAXN], rk[MAXN];
int endtree[MAXN], array[MAXN], dep[MAXN], id[MAXN];
struct node{
int from, to, next;
}map[MAXN];
void add(int u, int v)
{
map[++cnt] = (node){u, v, head[u]};
head[u] = cnt;
}
void dfs1(int u, int FA, int depth)
{
fa[u] = FA;
size[u]++;
dep[u] = depth;
for (int k = head[u];k;k = map[k].next){
int v = map[k].to;
if (v == FA)
{
continue;
}
dfs1(v, u, depth+1);
size[u] += size[v];
if (!son[u] || size[v] > size[son[u]])
{
son[u] = v;
}
}
}
void dfs2(int u, int top){
rk[u] = ++dfn;
id[dfn] = u;
Top[u] = top;
if (son[u])
{
dfs2(son[u], top);
}
for (int k = head[u];k;k = map[k].next){
int v = map[k].to;
if (v == fa[u] || v == son[u])
{
continue;
}
dfs2(v, v);
}
endtree[u] = dfn;
}
#define L(k) tree[(k)].l
#define R(k) tree[(k)].r
#define T(k) tree[(k)].tag
#define W(k) tree[(k)].w
#define _L k<<1
#define _R k<<1|1
struct Node{
LL l,r,w,tag;
}tree[MAXN];
void down(int k)
{
W(_L) = (W(_L) + T(k) * (R(_L) - L(_L) + 1)) % p;
W(_R) = (W(_R) + T(k) * (R(_R) - L(_R) + 1)) % p;
T(_L) = (T(_L) + T(k)) % p;
T(_R) = (T(_R) + T(k)) % p;
T( k) = 0;
}
void build_tree(int l, int r, int k)
{
L(k) = l;
R(k) = r;
if (l == r)
{
W(k) = array[id[l]];
return;
}
int mid = (l+r)>>1;
build_tree(l, mid, _L);
build_tree(mid+1, r, _R);
W(k) = (W(_L) + W(_R)) % p;
}
void interval_add(int l, int r, int k, int w)
{
if (l <= L(k) && r >= R(k))
{
T(k) = (T(k) + w) % p;
W(k) = (W(k) + w * (R(k) - L(k) + 1)) % p;
return;
}
down(k);
int mid = (L(k) + R(k)) >> 1;
if (mid < r) interval_add(l, r, _R, w);
if (mid >= l) interval_add(l, r, _L, w);
W(k) = (W(_L) + W(_R)) % p;
}
LL interval_query(int l, int r, int k)
{
if (l <= L(k) && r >= R(k))
{
return W(k);
}
down(k);
int mid = (L(k) + R(k)) >> 1;
LL ans = 0;
if (mid < r) ans += interval_query(l, r, _R);
if (mid >= l) ans += interval_query(l, r, _L);
W(k) = (W(_L) + W(_R)) % p;
return ans;
}
void LCA1(int x, int y, int w)
{
w %= p;
while (Top[x] != Top[y])
{
if (dep[Top[x]] < dep[Top[y]])
{
swap(x, y);
}
interval_add(rk[Top[x]], rk[x], 1, w);
x = fa[Top[x]];
}
if (dep[x] < dep[y])
{
swap(x, y);
}
interval_add(rk[y], rk[x], 1, w);
}
LL LCA2(int x, int y)
{
LL ans = 0;
while (Top[x] != Top[y])
{
if (dep[Top[x]] < dep[Top[y]])
{
swap(x, y);
}
ans += interval_query(rk[Top[x]], rk[x], 1);
x = fa[Top[x]];
}
if (dep[x] < dep[y])
{
swap(x, y);
}
ans += interval_query(rk[y], rk[x], 1);
return ans;
}
int main(void)
{
int m=0, n=0;
cin >> n >> m >> r >> p;
for (int i = 1;i <= n;i++)
{
cin >> array[i];
}
for (int i = 1;i < n;i++)
{
int x=0,y=0;
cin >> x >> y;
add(x, y);
add(y, x);
}
dfs1(r, r, 1);
dfs2(r, r);
build_tree(1, dfn, 1);
for (int i = 1;i <= m;i++)
{
int f=0, x=0, y=0, z=0;
cin >> f;
switch (f)
{
case 1:
cin >> x >> y >> z;
LCA1(x, y, z);
break;
case 2:
cin >> x >> y;
cout << LCA2(x, y) % p << endl;
break;
case 3:
cin >> x >> z;
interval_add(rk[x], endtree[x], 1, z);
break;
case 4:
cin >> x;
cout << interval_query(rk[x], endtree[x], 1) % p << endl;
break;
}
}
return 0;
}
这篇博客详细介绍了如何将树链剖分与线段树结合,用于解决动态维护区间信息的问题。通过轻重链剖分优化树结构,保证了查询和更新操作的时间复杂度。LCT(Link Cut Tree)模板展示了如何进行节点的深度优先搜索,构建拓扑结构,并提供了LCA(最近公共祖先)查询以及区间加权操作的方法。
2139

被折叠的 条评论
为什么被折叠?



