Ex - Substring Sort Editorial
by
Nyaan
別解を簡単に書きます。この問題は Generalized Suffix Tree (参考:Wikipedia) をオイラーツアーすれば解くことができます。これは LCP 配列を segtree に載せて segtree 上の二分探索を利用すれば \(\mathrm{O}(N \log N)\) 程度で簡潔に実装できます。(あるいは Cartesian Tree を利用すれば \(\mathrm{O}(N)\) で計算できます。)
- 実装例 (\(\mathrm{O}(N \log N)\))
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using namespace std;
#include "atcoder/segtree.hpp"
#include "atcoder/string.hpp"
using ll = long long;
constexpr int inf = 1001001001;
int f(int a, int b) { return min(a, b); }
int ti() { return inf; }
int main() {
ll N, Q;
cin >> N;
vector<string> S(N);
for (auto& s : S) cin >> s;
cin >> Q;
vector<ll> qs(Q);
for (auto& q : qs) cin >> q;
string T;
vector<pair<int, int>> derived;
for (int i = 0; i < N; i++) {
T += S[i];
for (int j = 0; j < (int)S[i].size(); j++) derived.emplace_back(i, j);
T.push_back('$');
derived.emplace_back(i, -1);
}
auto sa = atcoder::suffix_array(T);
auto lcp = atcoder::lcp_array(T, sa);
lcp.push_back(0);
atcoder::segtree<int, f, ti> seg(lcp);
ll qid = 0, sid = 0, pos = 0, sum = 0;
while (T[sa[sid]] == '$') sid++;
while (sid != (int)T.size()) {
int r = seg.max_right(sid, [&](int x) { return x > pos; });
int val = seg.prod(sid, r);
auto [m, mpos] = derived[sa[sid]];
val = min<int>(val, S[m].size() - mpos);
if (pos == val) {
pos = min<int>(pos, lcp[sid]), sid++;
continue;
}
ll nxtsum = sum + (r - sid + 1) * (val - pos);
while (qid != Q and qs[qid] <= nxtsum) {
ll diff = qs[qid] - 1 - sum;
ll i = diff / (r - sid + 1);
cout << m + 1 << " " << mpos + 1 << " " << mpos + 1 + pos + i << "\n";
qid++;
}
sum = nxtsum, pos = val;
}
}
posted:
last update: