本文以codeforces EDU Disjoint Sets Union为资料
content
Introduction
Mo’s algorithm and DSU
莫队算法在DSU的应用(询问区间)
分块,考虑到加减边需要符合一定的优先级(假设这里有个例子 ),对同一unit内的
(
l
,
r
)
(l, r)
(l,r),直接用DSU解决;对
l
l
l同一unit的询问,先加入剩下unit到
r
r
r的边,
s
a
v
e
save
save,再加入
l
l
l到unit的边,即得到当前询问区间的结果,
r
o
l
l
b
a
c
k
rollback
rollback
l
l
l到unit的边处理下一次询问。(加入
r
1
r1
r1到
r
2
r2
r2的边)。
s
a
v
e
save
save、
r
o
l
l
b
a
c
k
rollback
rollback用
s
t
a
c
k
stack
stack模拟
Dynamic Connectivity Offline
离线动态算法
有三种操作:
a
d
d
(
u
,
v
)
add(\bm{u}, \bm{v})
add(u,v)
r
e
m
o
v
e
(
u
,
v
)
remove(\bm{u}, \bm{v})
remove(u,v)
g
e
t
(
u
,
v
)
get(\bm{u}, \bm{v})
get(u,v)
考虑对
(
u
,
v
)
(u, v)
(u,v)的
a
d
d
add
add和
r
e
m
o
v
e
remove
remove成对考虑,即
(
u
,
v
,
t
a
d
d
,
t
r
e
m
o
v
e
)
(u, v, t_{add}, t_{remove})
(u,v,tadd,tremove)。该问题考虑时间戳,对当前时刻
t
t
t,若
t
a
d
d
⩽
t
⩽
t
r
e
m
o
v
e
t_{add} \leqslant t \leqslant t_{remove}
tadd⩽t⩽tremove,
(
u
,
v
,
t
a
d
d
,
t
r
e
m
o
v
e
)
(u, v, t_{add}, t_{remove})
(u,v,tadd,tremove)的边已加入且为消去;若
t
t
t不在
[
t
a
d
d
,
t
r
e
m
o
v
e
]
[t_{add}, t_{remove}]
[tadd,tremove],则不需考虑该边。那么可以用二分区间的算法考虑。
work(l, r, queries):
if l == r - 1:
for q in queries:
if q.type == get && q.t == l:
q.answer = get(q.u) == get(q.v)
return
save DSU
queries2 = {}
for q in queries:
if q.type == edge && [l, r) lies in [q.l, q.r):
union(q.u, q.v)
if (q.type == get && q.t in [l, r)) ||
(q.type == edge && [l, r) intersects [q.l, q.r)):
queries2.add(q)
m = (l + r) / 2
work(l, m, queries2)
work(m, r, queries2)
rollback DSU
problems & solutions
B. Number of Connected Components on Segments
莫队算法
C. Dynamic Connectivity Offline
一种可能可以减少内存的方法是使用线段树,但是笔者实际犯的错误是下面一种情况。所以可能是姿势问题。codeforces上关于该题的一个讨论
该题存在
m
=
0
m = 0
m=0的情况,注意导致
s
e
g
[
v
]
seg[v]
seg[v]超范围的情况。当然如果你们姿势好的话,可能不会有这个问题。