RT,wa on #2
// Problem: Forensic Examination
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF666E
// Memory Limit: 750 MB
// Time Limit: 6000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt")
#include <bits/stdc++.h>
using namespace std;
#define _f(i, a, b) for (int i = a; i <= b; ++i)
#define _d(i, a, b) for (int i = a; i >= b; --i)
using pii = pair<int, int>;
using ll = long long;
#define fi first
#define se second
static constexpr int N = 5e5 + 5, M = 5e4 + 5, V = 4e7 + 5;
char s[N], tt[N];
int n, m, l;
int ls[V], rs[V], mx[V], res[V], rt[N << 1], cnt;
int sz = 1, len[N], ff[23][N << 1], rpos[N];
vector<char> t[M];
vector<int> G[N << 1];
struct state {
int len, link;
map<char, int> nxt;
} st[N << 1];
void pushup(int p) {
if(mx[ls[p]] >= mx[rs[p]]) mx[p] = mx[ls[p]], res[p] = res[ls[p]];
else mx[p] = mx[rs[p]], res[p] = res[rs[p]];
}
int add(int p, int x, int l = 1, int r = n) {
if(!p) p = ++cnt;
if(l == r) return mx[p]++, res[p] = l, p;
int mid = (l + r) >> 1;
if(x <= mid) ls[p] = add(ls[p], x, l, mid);
else rs[p] = add(rs[p], x, mid + 1, r);
pushup(p);
return p;
}
int merge(int a, int b, int l = 1, int r = n) {
if(!a || !b) return a + b;
int root = ++cnt, mid = (l + r) >> 1;
if(l == r) {
mx[root] = mx[a] + mx[b], res[root] = l;
return root;
}
ls[root] = merge(ls[a], ls[b], l, mid);
rs[root] = merge(rs[a], rs[b], mid + 1, r);
pushup(root);
return root;
}
pii query(int p, int x, int y, int l = 1, int r = n) {
if(!p) return {0, 0};
if(x <= l && r <= y) return {res[p], mx[p]};
int mid = (l + r) >> 1;
pii lft = query(ls[p], x, y, l, mid);
pii rgt = query(rs[p], x, y, mid + 1, r);
return lft.se >= rgt.se ? lft : rgt;
}
int extend(int p, char c) {
if(st[p].nxt.count(c)) {
int q = st[p].nxt[c];
if(st[q].len == st[p].len + 1) return q;
else {
int clone = ++sz;
st[clone] = st[q], st[clone].len = st[p].len + 1, st[q].link = clone;
while(p && st[p].nxt[c] == q) st[p].nxt[c] = clone, p = st[p].link;
return clone;
}
}
int cur = ++sz;
st[cur].len = st[p].len + 1;
while(p && !st[p].nxt.count(c)) st[p].nxt[c] = cur, p = st[p].link;
if(!p) st[cur].link = 1;
else {
int q = st[p].nxt[c];
if(st[q].len == st[p].len + 1) st[cur].link = q;
else {
int clone = ++sz;
st[clone] = st[q], st[clone].len = st[p].len + 1;
st[q].link = st[cur].link = clone;
while(p && st[p].nxt[c] == q) st[p].nxt[c] = clone, p = st[p].link;
}
}
return cur;
}
void dfs(int x, int f) {
ff[0][x] = f;
_f(i, 1, 21) ff[i][x] = ff[i - 1][ff[i - 1][x]];
for(int v : G[x]) {
if(v == f) continue;
dfs(v, x);
rt[x] = merge(rt[x], rt[v]);
}
}
void solve() {
cin >> (s + 1) >> n, l = strlen(s + 1);
_f(i, 1, n) {
cin >> (tt + 1);
int lst = 1, ll = strlen(tt + 1);
_f(j, 1, ll)
t[i].emplace_back(tt[j]), lst = extend(lst, tt[j]);
}
_f(i, 1, n) {
int lst = 1;
for(char v : t[i])
lst = st[lst].nxt[v], rt[lst] = add(rt[lst], i);
}
int nowlen = 0, p = 1;
_f(i, 1, l) {
while(p && !st[p].nxt.count(s[i])) p = st[p].link, nowlen = st[p].len;
if(!p) nowlen = 0, p = 1;
else p = st[p].nxt[s[i]], ++nowlen;
len[i] = nowlen, rpos[i] = p;
}
_f(i, 2, sz) G[st[i].link].emplace_back(i);
dfs(1, 0);
cin >> m;
while(m--) {
int l, r, pl, pr, sl, p;
cin >> l >> r >> pl >> pr, sl = pr - pl + 1, p = rpos[pr];
if(len[pr] < sl) {
cout << l << ' ' << 0 << '\n';
continue;
}
_d(i, 21, 0) {
int j = ff[i][p];
if(st[st[j].link].len + 1 >= sl) p = j;
}
pii ret = query(rt[p], l, r);
if(ret.se == 0) ret.fi = l;
cout << ret.fi << ' ' << ret.se << '\n';
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
solve();
return 0;
}
// by zzzcr.