meaning of the title
Sol
Only suffix arrays + grumpy Mo team Suites set (n sqrt {n} log n) but absolutely can't run.
Positive solution is SAM + set heuristic combination + two-dimensional point / SAM + LCT
But I only have the first qwq
The first property is that the longest common suffix of two prefixes is len of LCA on their parent tree.
So let's consider the contribution of each LCA.
Sorting the queries offline by the right endpoint has an obvious property for the points in the subtree of the current point.
If there are four points (l, x, y, r) satisfying (l < x < y < r), then obviously \(l, r) is meaningless for this point (because each pair of points has the same contribution). That is to say, when we deal with subtrees, we actually have a bunch of points that are not useful. We can merge subtrees by set heuristic merging, that is, I have a bunch of point sets now, and then I consider which points will be useful after adding a new point, obviously only with its precursor/successor.
Because merging is a heuristic merge, the total complexity will not exceed (n\ log ^ 2 n)
After that, it's a two-dimensional max problem.
It's a bit self-closing qwq in tune
#include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define fi first #define se second #define pb push_back //#define int long long #define LL long long #define ull unsigned long long #define Fin(x) {freopen(#x".in","r",stdin);} #define Fout(x) {freopen(#x".out","w",stdout);} using namespace std; const int MAXN = 1e6 + 10, mod = 1e9 + 7, INF = 1e9 + 10; const double eps = 1e-9; template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;} template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;} template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;} template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);} template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;} template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;} template <typename A> inline void debug(A a){cout << a << '\n';} template <typename A> inline LL sqr(A x){return 1ll * x * x * x;} template <typename A, typename B> inline LL fp(A a, B p, int md = mod) {int b = 1;while(p) {if(p & 1) b = mul(b, a);a = mul(a, a); p >>= 1;}return b;} template <typename A> A inv(A x) {return fp(x, mod - 2);} inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N, M, ans[MAXN]; char s[MAXN]; vector<Pair> Q[MAXN], P[MAXN]; vector<int> v[MAXN]; set<int> st[MAXN]; int ch[MAXN][2], len[MAXN], fa[MAXN], las = 1, root = 1, tot = 1; void insert(int x, int id) { int now = ++tot, pre = las; las = now; len[now] = len[pre] + 1; st[now].insert(id); for(; pre && !ch[pre][x]; pre = fa[pre]) ch[pre][x] = now; if(!pre) fa[now] = root; else { int q = ch[pre][x]; if(len[q] == len[pre] + 1) fa[now] = q; else { int nq = ++tot; fa[nq] = fa[q]; len[nq] = len[pre] + 1; memcpy(ch[nq], ch[q], sizeof(ch[q])); for(; pre && ch[pre][x] == q; pre = fa[pre]) ch[pre][x] = nq; fa[now] = fa[q] = nq; } } } void dfs(int x) { set<int> &S = st[x]; for(auto &to : v[x]) { dfs(to); set<int> &Sto = st[to]; if(Sto.size() > S.size()) swap(Sto, S); for(auto &nxt: Sto) { auto pos = S.insert(nxt).fi; if(pos != S.begin()) { auto pre = --pos; pos++; // printf("%d %d %d\n", *pos, *pre, len[x]); P[*pos].pb({*pre, len[x]}); } if((++pos) != S.end()) { pos--; auto nxt = ++pos; pos--; //printf("%d %d\n", *pos, *nxt); P[*nxt].pb({*pos, len[x]}); } S.erase(nxt); } for(auto &nxt: Sto) S.insert(nxt); } } void Build() { for(int i = 1; i <= tot; i++) v[fa[i]].push_back(i); dfs(1); for(int i = 1; i <= N; i++) sort(Q[i].begin(), Q[i].end()), sort(P[i].begin(), P[i].end()); } int mx[MAXN]; #define lb(x) (x & (-x)) void Add(int x, int val) { x = N - x + 1; while(x <= N) chmax(mx[x], val), x += lb(x); } int Query(int x) { x = N - x + 1; int ans = 0; while(x) chmax(ans, mx[x]), x -= lb(x); return ans; } void solve() { for(int i = 1; i <= N; i++) { int cur = Q[i].size() - 1; for(int j = P[i].size() - 1; j >= 0; j--) { while((~cur) && Q[i][cur].fi > P[i][j].fi) ans[Q[i][cur].se] = Query(Q[i][cur].fi), cur--; Add(P[i][j].fi, P[i][j].se); } while(~cur) ans[Q[i][cur].se] = Query(Q[i][cur].fi), cur--; } } signed main() { //freopen("a.in", "r", stdin); N = read(); M = read(); scanf("%s", s + 1); for(int i = 1; i <= N; i++) insert(s[i] - '0', i); for(int i = 1; i <= M; i++) { int l = read(), r = read(); Q[r].pb({l, i}); } Build(); solve(); for(int i = 1; i <= M; i++) cout << ans[i] << '\n'; return 0; }