import
java.util.Arrays;
class
Query {
int
L, R;
public
Query(
int
L,
int
R)
{
this
.L = L;
this
.R = R;
}
}
class
Suffix
implements
Comparable<Suffix> {
int
index;
int
[] rank =
new
int
[
2
];
public
Suffix(
int
index) {
this
.index = index; }
@Override
public
int
compareTo(Suffix other)
{
return
(
this
.rank[
0
] == other.rank[
0
])
? Integer.compare(
this
.rank[
1
], other.rank[
1
])
: Integer.compare(
this
.rank[
0
], other.rank[
0
]);
}
}
public
class
LongestCommonExtension {
static
int
minVal(
int
x,
int
y)
{
return
(x < y) ? x : y;
}
static
int
maxVal(
int
x,
int
y)
{
return
(x > y) ? x : y;
}
static
int
compare(Suffix a, Suffix b)
{
return
(a.rank[
0
] == b.rank[
0
])
? Integer.compare(a.rank[
1
], b.rank[
1
])
: Integer.compare(a.rank[
0
], b.rank[
0
]);
}
static
int
[] buildSuffixArray(String txt)
{
int
n = txt.length();
Suffix[] suffixes =
new
Suffix[n];
for
(
int
i =
0
; i < n; i++) {
suffixes[i] =
new
Suffix(i);
suffixes[i].rank[
0
] = txt.charAt(i) -
'a'
;
suffixes[i].rank[
1
]
= (i +
1
) < n ? txt.charAt(i +
1
) -
'a'
: -
1
;
}
Arrays.sort(suffixes);
int
[] ind =
new
int
[n];
for
(
int
k =
4
; k <
2
* n; k = k *
2
) {
int
rank =
0
;
int
prev_rank = suffixes[
0
].rank[
0
];
suffixes[
0
].rank[
0
] = rank;
ind[suffixes[
0
].index] =
0
;
for
(
int
i =
1
; i < n; i++) {
if
(suffixes[i].rank[
0
] == prev_rank
&& suffixes[i].rank[
1
]
== suffixes[i -
1
].rank[
1
]) {
prev_rank = suffixes[i].rank[
0
];
suffixes[i].rank[
0
] = rank;
}
else
{
prev_rank = suffixes[i].rank[
0
];
suffixes[i].rank[
0
] = ++rank;
}
ind[suffixes[i].index] = i;
}
for
(
int
i =
0
; i < n; i++) {
int
nextindex = suffixes[i].index + k /
2
;
suffixes[i].rank[
1
]
= (nextindex < n)
? suffixes[ind[nextindex]].rank[
0
]
: -
1
;
}
Arrays.sort(suffixes);
}
int
[] suffixArr =
new
int
[n];
for
(
int
i =
0
; i < n; i++) {
suffixArr[i] = suffixes[i].index;
}
return
suffixArr;
}
static
int
[] kasai(String txt,
int
[] suffixArr)
{
int
n = suffixArr.length;
int
[] lcp =
new
int
[n];
int
[] invSuff =
new
int
[n];
for
(
int
i =
0
; i < n; i++) {
invSuff[suffixArr[i]] = i;
}
int
k =
0
;
for
(
int
i =
0
; i < n; i++) {
if
(invSuff[i] == n -
1
) {
k =
0
;
continue
;
}
int
j = suffixArr[invSuff[i] +
1
];
while
(i + k < n && j + k < n
&& txt.charAt(i + k)
== txt.charAt(j + k)) {
k++;
}
lcp[invSuff[i]] = k;
if
(k >
0
) {
k--;
}
}
return
lcp;
}
static
int
LCE(
int
[] lcp,
int
[] invSuff,
int
n,
int
L,
int
R)
{
if
(L == R) {
return
n - L;
}
int
low = minVal(invSuff[L], invSuff[R]);
int
high = maxVal(invSuff[L], invSuff[R]);
int
length = lcp[low];
for
(
int
i = low +
1
; i < high; i++) {
if
(lcp[i] < length) {
length = lcp[i];
}
}
return
length;
}
static
void
LCEQueries(String txt,
int
[] suffixArr,
Query[] q)
{
int
n = txt.length();
int
[] invSuff =
new
int
[n];
for
(
int
i =
0
; i < n; i++) {
invSuff[suffixArr[i]] = i;
}
int
[] lcp = kasai(txt, suffixArr);
for
(Query query : q) {
int
L = query.L;
int
R = query.R;
System.out.println(
"LCE ("
+ L +
", "
+ R
+
") = "
+ LCE(lcp, invSuff, n, L, R));
}
}
public
static
void
main(String[] args)
{
String txt =
"abbababba"
;
int
n = txt.length();
Query[] queries
= {
new
Query(
1
,
2
),
new
Query(
1
,
6
),
new
Query(
0
,
5
) };
int
[] suffixArr = buildSuffixArray(txt);
LCEQueries(txt, suffixArr, queries);
}
}