后缀数组模版

后缀数组模版

cpp
// O(n log^2 n) 倍增法,n 在 1e5 级别足够快;更大规模可换成基数排序做到 O(n log n)
struct SuffixArray {
    int n;
    string s;
    vector<int> sa, rk, height;

    SuffixArray(const string& str) : s(str) {
        n = s.size();
        build();
    }

    void build() {
        sa.resize(n);
        rk.resize(n);
        vector<int> tmp(n);

        for (int i = 0; i < n; i++) rk[i] = s[i];
        for (int i = 0; i < n; i++) sa[i] = i;

        for (int k = 1; ; k <<= 1) {
            auto cmp = [&](int a, int b) {
                if (rk[a] != rk[b]) return rk[a] < rk[b];
                int ra = a + k < n ? rk[a + k] : -1;
                int rb = b + k < n ? rk[b + k] : -1;
                return ra < rb;
            };
            sort(sa.begin(), sa.end(), cmp);
            tmp[sa[0]] = 0;
            for (int i = 1; i < n; i++) tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0);
            rk = tmp;
            if (rk[sa[n - 1]] == n - 1) break;
        }

        // height[i] = LCP(sa[i], sa[i-1])
        height.assign(n, 0);
        int k = 0;
        for (int i = 0; i < n; i++) {
            if (rk[i] == 0) { k = 0; continue; }
            if (k > 0) k--;
            int j = sa[rk[i] - 1];
            while (i + k < n && j + k < n && s[i + k] == s[j + k]) k++;
            height[rk[i]] = k;
        }
    }
};
李超线段树模版
长链剖分模版