这个题确实思维方向非常重要!
如果用后缀数组做,就转化为区间众数,一脸不可做。(当然莫对+堆还是可以的。。)
这个题应该用后缀自动机或者后缀树来做。这样问题就是子树众数,就可以用线段树合并一个log搞定。(为什么我一个log比别人一个log+一个根号还慢啊)
#include
#include
#include
#include
#include
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
#define LL long long
using namespace std;
const int MAXN = 500005;
const int MAXS = 1230000;
int N, M;
char s[MAXN];
int ch[MAXS][27], fa[MAXS], ml[MAXS], anc[21][MAXS], pos[MAXN], rt[MAXS], que[MAXS];
int tot = 1, last = 1;
inline void extend(int c)
{
int p = last;
int np = last = ++tot;
ml[np] = ml[p] + 1;
while (p&&!ch[p][c]) ch[p][c] = np, p = fa[p];
if (!p) { fa[np] = 1; return; }
int q = ch[p][c];
if (ml[p]+1 == ml[q]) fa[np] = q;
else {
int nq = ++tot; ml[nq] = ml[p]+1;
memcpy(ch[nq], ch[q], sizeof ch[q]);
fa[nq] = fa[q];
fa[np] = fa[q] = nq;
while (ch[p][c]==q) ch[p][c] = nq, p = fa[p];
}
}
inline int getpos(int l, int r)
{
int len = r-l+1, p = pos[r];
erp(i,20,0) if(ml[anc[i][p]] >= len) p = anc[i][p];
return p;
}
void toposort()
{
static int ws[MAXS];
rep(i, 1, tot) ws[ml[i]] ++;
rep(i, 1, tot) ws[i] += ws[i-1];
rep(i, 1, tot) que[ws[ml[i]]--] = i;
}
int ncnt;
#define lch(x) tr[x].lch
#define rch(x) tr[x].rch
struct info { int mx, id; };
struct Node {
info t;
int lch, rch;
} tr[MAXS*22];
info operator | (const info&a, const info&b)
{
if (a.mx > b.mx) return a;
if (a.mx < b.mx) return b;
return a.id < b.id ? a : b;
}
void ins(int&p, int v, int l=1, int r=M)
{
if (!p) p = ++ncnt;
if (l==r) { tr[p].t.mx ++, tr[p].t.id = l; return; }
int mid = (l+r)>>1;
if (v<=mid) ins(lch(p), v, l, mid);
else ins(rch(p), v, mid+1, r);
tr[p].t = tr[lch(p)].t | tr[rch(p)].t;
}
int Merge(int x, int y, int l=1, int r=M)
{
if (!x||!y) return x|y;
int z = ++ncnt;
if (l==r) {
tr[z].t = (info){tr[x].t.mx+tr[y].t.mx, l};
return z;
}
int mid = (l+r)>>1;
lch(z) = Merge(lch(x), lch(y), l, mid);
rch(z) = Merge(rch(x), rch(y), mid+1, r);
tr[z].t = tr[lch(z)].t | tr[rch(z)].t;
return z;
}
info ask(int p, int L, int R, int l=1, int r=M)
{
if (!p) return (info){0,0};
if (l>=L && r<=R) return tr[p].t;
int mid = (l+r)>>1;
if (R<=mid) return ask(lch(p), L, R, l, mid);
if (L>mid) return ask(rch(p), L, R, mid+1, r);
return ask(lch(p), L, R, l, mid) | ask(rch(p), L, R, mid+1, r);
}
void init()
{
toposort();
erp(i,tot,1)
{
int u = que[i];
if (fa[u]) rt[fa[u]] = Merge(rt[fa[u]], rt[u]);
}
rep(i,1,tot) anc[0][i] = fa[i];
rep(i,1,20) rep(j,1,tot) anc[i][j] = anc[i-1][ anc[i-1][j] ];
}
int main()
{
scanf("%s", s+1);
N = strlen(s+1);
rep(i,1,N) extend(s[i]-'a'), pos[i] = last;
extend(26);
scanf("%d", &M);
rep(i, 1, M)
{
scanf("%s", s+1);
for (int j = 1; s[j]; ++j)
extend(s[j]-'a'), ins(rt[last], i);
extend(26);
}
init();
int Q, a, b, l, r, p;
scanf("%d", &Q);
while (Q--)
{
scanf("%d%d%d%d", &a, &b, &l, &r);
p = getpos(l, r);
info tmp = ask(rt[p], a, b);
if (tmp.mx == 0) printf("%d 0\n", a);
else printf("%d %d\n", tmp.id, tmp.mx);
}
return 0;
}