<p>Given a string <code>s</code>, consider all <em>duplicated substrings</em>: (contiguous) substrings of s that occur 2 or more times.&nbsp;The occurrences&nbsp;may overlap.</p>

<p>Return <strong>any</strong> duplicated&nbsp;substring that has the longest possible length.&nbsp;If <code>s</code> does not have a duplicated substring, the answer is <code>&quot;&quot;</code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<pre><strong>Input:</strong> s = "banana"
<strong>Output:</strong> "ana"
</pre><p><strong class="example">Example 2:</strong></p>
<pre><strong>Input:</strong> s = "abcd"
<strong>Output:</strong> ""
</pre>
<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>2 &lt;= s.length &lt;= 3 * 10<sup>4</sup></code></li>
	<li><code>s</code> consists of lowercase English letters.</li>
</ul>

class Solution {
public:
    string longestDupSubstring(string s) {

        int n = s.length();
        vector<long long> hash1(n), hash2(n), p_pow1(n), p_pow2(n);

        auto rolling_hash = [&] (vector<long long> &hash, long long p, long long M, vector<long long> &p_pow) {
            hash[0] = s[0] - 'a' + 1; p_pow[0] = 1;
            for (int i = 1; i < n; i++) {
                hash[i] = (hash[i - 1] * p % M + s[i] - 'a' + 1) % M;
                p_pow[i] = p_pow[i - 1] * p % M;
            }
        };

        auto sub_hash = [&] (int l, int r, vector<long long> &hash, long long M, vector<long long> &p_pow) {
            if (l == 0) return hash[r];
            return ((hash[r] - hash[l - 1] * p_pow[r - l + 1]) % M + M) % M;
        };

        rolling_hash(hash1, 31LL, 999999929LL, p_pow1);
        rolling_hash(hash2, 37LL, 999999937LL, p_pow2);

        auto suffix_array = [&](const string & s) -> vector<int> {
            int N = s.length(), stp, cnt;
            vector<vector<int>> P(17, vector<int>(N));
            vector<int> suffixArr(N);

            struct entry {
                int nr[2], p;
            };

            vector<entry> L(N);
            for (int i = 0; i < N; i++) P[0][i] = s[i] - 'a';

            for (stp = 1, cnt = 1; cnt < N; stp++, cnt *= 2) {
                for (int i = 0; i < N; i++) {
                    L[i].nr[0] = P[stp - 1][i];
                    L[i].nr[1] = i + cnt < N ? P[stp - 1][i + cnt] : -1;
                    L[i].p = i;
                }

                sort(L.begin(), L.end(), [](entry a, entry b) {
                    return a.nr[0] == b.nr[0] ? (a.nr[1] < b.nr[1] ? 1 : 0) : (a.nr[0] < b.nr[0] ? 1 : 0);
                });

                for (int i = 0; i < N; i++)
                    P[stp][L[i].p] = i > 0 && L[i].nr[0] == L[i - 1].nr[0] && L[i].nr[1] == L[i - 1].nr[1]
                                     ? P[stp][L[i - 1].p]
                                     : i;
            }
            for (int i = 0; i < N; i++) {
                suffixArr[i] = L[i].p;
            }

            return suffixArr;
        };


        vector<int> suff_arr = suffix_array(s);
        int maxi = 0; int idx = -1;

        auto checker = [&] (int x, int i, int j) {
            if (!x) return true;
            int l1 = i, r1 = i + x - 1, l2 = j, r2 = j + x - 1;
            int a = sub_hash(l1, r1, hash1, 999999929LL, p_pow1);
            int b = sub_hash(l1, r1, hash2, 999999937LL, p_pow2);
            int c = sub_hash(l2, r2, hash1, 999999929LL, p_pow1);
            int d = sub_hash(l2, r2, hash2, 999999937LL, p_pow2);

            if (a == c && b == d) return true;
            else return false;
        };

        for (int i = 0; i < n - 1; i++) {
            int sz = min(n - suff_arr[i], n - suff_arr[i + 1]);
            int lo = 0, hi = sz + 1, mi;

            while (hi - lo > 1) {
                mi = lo + (hi - lo ) / 2;
                if (checker(mi, suff_arr[i], suff_arr[i + 1])) lo = mi;
                else hi = mi;
            }
            if (maxi < lo) {
                maxi = lo; idx = suff_arr[i];
            }
        }
        if (!maxi) return "";
        return s.substr(idx, maxi);
    }
};
54500