dsu on tree

dsu on tree

可以用来解决一些有下列性质的问题:

  1. 对子树询问
  2. 没有修改

算法

算法步骤如下:

  • 遍历的一个节点
    • 递归所有的轻儿子
    • 递归重儿子
    • 统计轻儿子对答案的影响
    • 计算答案
    • 如果自己是轻儿子,消除影响
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void add(int u, int father, int delta, int exc)
{
//modify

for (int i = head[u]; i; i = nextx[i])
{
int v = vet[i];
if (v != father && v != exc)
{
add(v, u, delta, exc);
}
}
}

void solve(int u, int father, int cas)
{
for (int i = head[u]; i; i = nextx[i])
{
int v = vet[i];
if (v != father && v != son[u])
{
solve(v, u, 0);
}
}
if (son[u])
{
solve(son[u], u, 1);
}
add(u, father, 1, son[u]);

//calc ans

if (cas == 0)
{
add(u, father, -1, 0);

//clear
}
}

时间复杂度

类似于树链剖分,可以证明对于一个点到根上的路径,轻边的边数是不会超过$logn$条的,因为经过一条轻边意味着子树大小至少乘$2$

那么根据算法,可以发现每个点需要消除影响的次数为$O(logn)$次,不需要消除影响的次数为$O(1)$次,那么总的时间复杂度为$O(nlogn)$

参考资料

# , 算法
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×