Fail 树
我们在写
K
M
P
KMP
KMP 时会求出来长度为
N
o
d
e
Node
Node 的前缀最长
b
o
r
d
e
r
border
border 的长度
N
e
x
t
[
N
o
d
e
]
Next[Node]
Next[Node]。
根据前面的理论,对于一个字符串
S
S
S,它的
b
o
r
d
e
r
border
border 集合等于它的最长
b
o
r
d
e
r
border
border 的 (
b
o
r
d
e
r
border
border 集合 + 本身)。
对于长度为
N
N
N 的字符串,我们建立
N
+
1
N + 1
N+1 个点,编号为
0
0
0 到
N
N
N。对于点
N
o
d
e
Node
Node,我们连一条单向边
(
N
e
x
t
[
N
o
d
e
]
,
N
o
d
e
)
(Next[Node], Node)
(Next[Node],Node),则会形成一颗有根树,树根为
0
0
0,这棵树就叫做
f
a
i
l
fail
fail 树。
Fail 树的性质
- 对于一个点 N o d e Node Node,它的 b o r d e r border border 集合便是它到树根的路径上所有点对应的前缀。
- 点 N o d e 1 Node1 Node1 和点 N o d e 2 Node2 Node2 在 f a i l fail fail 树的 LCA 指的是长度分别是 N o d e 1 Node1 Node1 和 N o d e 2 Node2 Node2 的前缀的最长公共 B o r d e r Border Border。
解决模板题 P5829
LCA
方法
使用倍增。
记
F
a
[
N
o
d
e
]
[
i
]
Fa[Node][i]
Fa[Node][i] 表示点
N
o
d
e
Node
Node 的
2
i
2^i
2i 级祖先,
F
a
[
N
o
d
e
]
[
0
]
Fa[Node][0]
Fa[Node][0] 就是它的父节点。
那么对于
i
⩾
1
i \geqslant 1
i⩾1,我们有转移式:
F
a
[
N
o
d
e
]
[
i
]
=
F
a
[
F
a
[
N
o
d
e
]
[
i
−
1
]
]
[
i
−
1
]
Fa[Node][i]=Fa[Fa[Node][i-1]][i-1]
Fa[Node][i]=Fa[Fa[Node][i−1]][i−1]。
也就是说,点
N
o
d
e
Node
Node 的
2
i
2^i
2i 级祖先就是点
N
o
d
e
Node
Node 的
2
i
−
1
2^{i-1}
2i−1 级祖先 的
2
i
−
1
2^{i-1}
2i−1 级祖先。(
2
i
−
1
+
2
i
−
1
=
2
i
−
1
∗
2
=
2
i
2^{i-1}+2^{i-1}=2^{i-1}*2=2^i
2i−1+2i−1=2i−1∗2=2i)
对于树上的每个点我们都能处理
F
a
Fa
Fa 的值。
求
N
o
d
e
1
Node1
Node1 和
N
o
d
e
2
Node2
Node2 的 LCA 时,假设深度
D
e
p
[
N
o
d
e
1
]
>
D
e
p
[
N
o
d
e
2
]
Dep[Node1] > Dep[Node2]
Dep[Node1]>Dep[Node2],我们先计算出深度差
D
i
f
=
D
e
p
[
N
o
d
e
1
]
−
D
e
p
[
N
o
d
e
2
]
Dif = Dep[Node1] - Dep[Node2]
Dif=Dep[Node1]−Dep[Node2],然后把
D
e
p
Dep
Dep 转成二进制,通过倍增跳跃使得点
N
o
d
e
1
Node1
Node1 和点
N
o
d
e
2
Node2
Node2 深度相同。
然后,若点
N
o
d
e
1
Node1
Node1 和点
N
o
d
e
2
Node2
Node2 相同,则
N
o
d
e
1
Node1
Node1 (或
N
o
d
e
2
Node2
Node2) 就是 LCA。
否则,我们先考虑
2
20
2^{20}
220 (
2
2
2 的某个次幂,只要满足
>
N
> N
>N 就行),如果
N
o
d
e
1
Node1
Node1 和
N
o
d
e
2
Node2
Node2 同时跳
2
20
2^{20}
220 级祖先仍然不同,那么就跳,否则不动;接着枚举
2
19
2^{19}
219,以此类推。(注意不能越界)
到最后,
N
o
d
e
1
Node1
Node1,
N
o
d
e
2
Node2
Node2 只需要再跳一步就是 LCA 了。时间复杂度是
Θ
(
log
N
)
\Theta(\log N)
Θ(logN) 的。
代码(LCA)
void DFS(int Current, int Previous) {
// std::cout << "DFS\n";
Tree[Current][0] = Previous;
for (int i = 1; i <= Log2[Dep[Current]]; i++) {
Tree[Current][i] = Tree[Tree[Current][i - 1]][i - 1];
}
for (int Node2 : Gr[Current]) {
Dep[Node2] = Dep[Current] + 1;
DFS(Node2, Current);
}
}
int LCA(int A, int B) {
//std::cout << "LCA\n";
if (Dep[A] < Dep[B]) std::swap(A, B);
while (Dep[A] > Dep[B]) A = Tree[A][Log2[Dep[A] - Dep[B]]];
if (A == B) return A;
for (int i = Log2[Dep[A]]; i >= 0; i--) {
if(Tree[A][i] != Tree[B][i]) {
A = Tree[A][i];
B = Tree[B][i];
}
}
return Tree[A][0];
}
代码 (P5829)
std::vector<int> Gr[1000005];
std::vector<int> Next;
std::vector<int> GetNext(std::string Str) {
//std::cout << "Next\n";
static std::vector<int> Result(Str.size() + 3, 0);
int Len = Str.size() - 1;
int j = 0;
for (int i = 2; i <= Len; i++) {
while (j && Str[j + 1] != Str[i]) j = Result[j];
if (Str[j + 1] == Str[i]) j++;
Result[i] = j;
}
return Result;
}
int Tree[1000005][22];
int Dep[1000005], Log2[1000005];
void DFS(int Current, int Previous) {
// std::cout << "DFS\n";
Tree[Current][0] = Previous;
for (int i = 1; i <= Log2[Dep[Current]]; i++) {
Tree[Current][i] = Tree[Tree[Current][i - 1]][i - 1];
}
for (int Node2 : Gr[Current]) {
Dep[Node2] = Dep[Current] + 1;
DFS(Node2, Current);
}
}
int LCA(int A, int B) {
//std::cout << "LCA\n";
if (Dep[A] < Dep[B]) std::swap(A, B);
while (Dep[A] > Dep[B]) A = Tree[A][Log2[Dep[A] - DepB]]];
if (A == B) return A;
for (int i = Log2[Dep[A]]; i >= 0; i--) {
if(Tree[A][i] != Tree[B][i]) {
A = Tree[A][i];
B = Tree[B][i];
}
}
return Tree[A][0];
}
std::vector<int> P5829(std::string Str, int M, std::vector<int> P, std::vector<int> Q) {
//std::cout << "P5829\n";
Dep[0] = 0;
Str = '#' + Str;
Log2[1] = 0;
int Len = Str.size() - 1;
for (int i = 2; i < 1000005; i++) {
Log2[i] = Log2[i - 1] + ((i & -i) == i);
}
Next = GetNext(Str);
for (int i = 1; i <= Len; i++) Gr[Next[i]].push_back(i);
DFS(0, 0);
std::vector<int> Result(0);
for (int i = 0; i < M; i++) {
Result.push_back(LCA(Tree[P[i]][0], Tree[Q[i]][0]));
}
return Result;
}