题意:
kmlver有一个字符串S, 该字符串仅由小写字母组成,你需要分别回答Q次询问,每次询问由4个整数组成: l 1 , r 1 , l 2 , r 2 ( 1 ≤ l 1 ≤ r 1 ≤ ∣ S ∣ , 1 ≤ l 2 ≤ r 2 ≤ ∣ S ∣ ) l1, r1, l2, r2 (1 ≤ l1 ≤ r1 ≤ |S|, 1 ≤ l2 ≤ r2 ≤ |S|) l1,r1,l2,r2(1≤l1≤r1≤∣S∣,1≤l2≤r2≤∣S∣),你需要统计子串 S l 1 S_{l_1} Sl1 S l 1 + 1 S_{l_1+1} Sl1+1 S l 1 + 2 S_{l_1+2} Sl1+2… S r 1 S_{r1} Sr1在子串 S l 2 S_{l_2} Sl2 S l 2 + 1 S_{l_2+1} Sl2+1 S l 2 + 2 S_{l_2+2} Sl2+2… S r 2 S_{r2} Sr2的出现次数。
题解:
我们可以先用后缀数组处理S串,则子串A在S串中的出现次数,即为S中所有满足与A串的LCP ≥ len(A)的后缀的个数。
因为两个后缀的LCP是它们在后缀数组中height[l + 1, r]的最小值(区间最值问题直接用RMQ即可), 那么我们先找到A串在后缀数组中的rank,然后二分找到区间,使排名在这个区间中每个后缀都满足与A串的LCP ≥ len(A),接下来就简单了,我们只需要知道排名在这个区间中的后缀有多少个满足它的SA是在 [ l 2 , r 2 − ( r 1 − l 1 + 1 ) + 1 ] [l2, r2 - (r1 - l1 + 1) + 1] [l2,r2−(r1−l1+1)+1]中,这个直接用主席树查找即可。
代码:
/*
* @Author : Nightmare
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 100005
#define M 1000005
#define mod 10007
#define inf 0x3f3f3f3f
char str[N]; int root[N], tot;
struct SA{
static const int maxn = 1e5 + 5;
int h[maxn], rk[maxn], sa[maxn], y[maxn], c[maxn];
void build(int n, int m) {
for (int i = 0; i <= m; i ++) c[i] = 0;
for (int i = 1; i <= n; i ++) c[rk[i] = (str[i] - 'a' + 1)] ++;
for (int i = 1; i <= m; i ++) c[i] += c[i - 1];
for (int i = n; i >= 1; i --) sa[c[rk[i]]--] = i;
for (int k = 1; k <= n; k <<= 1) {
int p = 0;
for (int i = n - k + 1; i <= n; i ++) y[++p] = i;
for (int i = 1; i <= n; i ++) if (sa[i] > k) y[++p] = sa[i] - k;
for (int i = 0; i <= m; i ++) c[i] = 0;
for (int i = 1; i <= n; i ++) c[rk[i]]++;
for (int i = 1; i <= m; i ++) c[i] += c[i - 1];
for (int i = n; i >= 1; i --) sa[c[rk[y[i]]]--] = y[i];
swap(rk, y); rk[sa[1]] = p = 1;
for (int i = 2; i <= n; i ++)
rk[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p : ++p);
if (p >= n) break;
m = p;
}
for (int i = 1, k = 0; i <= n; i ++) {
if (k) -- k; int j = sa[rk[i] - 1];
while (str[i + k] == str[j + k]) k ++;
h[rk[i]] = k;
}
}
}sa;
struct RMQ{
static const int maxn = 1e5 + 5;
static const int maxm = 20;
int f[maxn][maxm], lg[maxn];
inline void init(int n){
for(int i = 1 ; i <= n ; i ++) f[i][0] = sa.h[i];
for(int i = 2 ; i <= n ; i ++) lg[i] = lg[i >> 1] + 1;
for(int j = 1 ; (1 << j) <= n ; j ++)
for(int i = 1 ; i + (1 << j) - 1 <= n ; i ++)
f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
inline int query(int l, int r){
if(l > r) swap(l, r); l ++;
int k = lg[r - l + 1];
return min(f[l][k], f[r - (1 << k) + 1][k]);
}
}rmq;
struct Segment_Tree{
static const int maxn = 1e5 + 5;
struct node{ int l, r, sum; }t[maxn * 32];
void update(int l, int r, int &x, int y, int k){
t[++tot] = t[y]; t[tot].sum ++; x = tot;
if(l == r) return ;
int mid = (l + r) >> 1;
if(k <= mid) update(l, mid, t[x].l, t[y].l, k);
else update(mid + 1, r, t[x].r, t[y].r, k);
}
int query(int l, int r, int x, int y, int k){
if(l == r) return l;
int mid = (l + r) >> 1, sum = t[t[y].l].sum - t[t[x].l].sum;
if(k <= sum) return query(l, mid, t[x].l, t[y].l, k);
else return query(mid + 1, r, t[x].r, t[y].r, k - sum);
}
int rk(int l,int r,int x,int y,int k) {
if (k == 0) return 0;
if (l == r) return t[y].sum - t[x].sum;
int mid = l + r >> 1, sum = 0;
if (mid >= k) sum = rk(l, mid, t[x].l, t[y].l, k);
else sum = t[t[y].l].sum - t[t[x].l].sum + rk(mid + 1, r, t[x].r, t[y].r, k);
return sum;
}
}seg;
inline int get_l(int x, int len, int n){
int l = 1, r = x, ans = x;
while(l <= r){
int mid = (l + r) >> 1;
if(rmq.query(mid, x) >= len) r = mid - 1, ans = mid;
else l = mid + 1;
}
return ans;
}
inline int get_r(int x, int len, int n){
int l = x, r = n, ans = x;
while(l <= r){
int mid = (l + r) >> 1;
if(rmq.query(x, mid) >= len || mid == x) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
inline void solve(){
int n; scanf("%d", &n);
scanf("%s", str + 1);
sa.build(n, 30);
rmq.init(n);
for(int i = 1 ; i <= n ; i ++) seg.update(1, n, root[i], root[i - 1], sa.sa[i]);
int Q; scanf("%d", &Q);
for(int cas = 1 ; cas <= Q ; cas ++){
int l1, r1, l2, r2; scanf("%d %d %d %d", &l1, &r1, &l2, &r2);
if(r1 - l1 > r2 - l2){ puts("0"); continue; }
int l = get_l(sa.rk[l1], r1 - l1 + 1, n), r = get_r(sa.rk[l1], r1 - l1 + 1, n);
int ansl = seg.rk(1, n, root[l - 1], root[r], l2 - 1);
int ansr = seg.rk(1, n, root[l - 1], root[r], r2 - (r1 - l1 + 1) + 1);
cout << ansr - ansl << '\n';
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("D:\\in.txt", "r", stdin);
#endif
solve();
#ifndef ONLINE_JUDGE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}