传送门
题解:
线段树维护fail树,然后t串暴力在s串fail树上跳,对每个后缀求出重合最多的一部分,然后自己再求一次即可。
时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
#include
using namespace std;
const int N=1e6+50;
struct SAM {
char ch[N];
int len,last,tot;
int pos[N],fail[N],son[N][26],l[N];
inline void extend(int i,int c) {
int p=pos[i]=++tot; l[p]=l[last]+1;
while(p && !son[last][c]) son[last][c]=p, last=fail[last];
if(!last) fail[p]=1;
else {
int q=son[last][c];
if(l[q]==l[last]+1) fail[p]=q;
else {
int np=++tot; memcpy(son[np],son[q],sizeof(son[np]));
fail[np]=fail[q]; fail[q]=fail[p]=np; l[np]=l[last]+1;
while(last && son[last][c]==q) son[last][c]=np, last=fail[last];
}
} last=p;
}
inline void init() {
for(int i=1;i<=tot;i++) memset(son[i],0,sizeof(son[i])), pos[i]=fail[i]=l[i]=0;
last=tot=1;
scanf("%s",ch+1); len=strlen(ch+1);
for(int i=1;i<=len;i++) extend(i,ch[i]-'a');
}
} s,t;
int rt[N],lc[N*30],rc[N*30],mx[N*30],tot;
inline void inc(int &k,int l,int r,int p) {
if(!k) k=++tot;
if(l==r) {mx[k]=p; return;}
int mid=(l+r)>>1;
(p<=mid) ? inc(lc[k],l,mid,p) : inc(rc[k],mid+1,r,p);
mx[k]=max(mx[lc[k]],mx[rc[k]]);
}
inline int ask(int k,int l,int r,int L,int R) {
if(!k) return 0;
if(L<=l && r<=R) return mx[k];
int mid=(l+r)>>1;
if(R<=mid) return ask(lc[k],l,mid,L,R);
else if(L>mid) return ask(rc[k],mid+1,r,L,R);
else return max(ask(lc[k],l,mid,L,R),ask(rc[k],mid+1,r,L,R));
}
inline int merge(int x,int y) {
if(!x) return y;
if(!y) return x;
int z=++tot;
lc[z]=merge(lc[x],lc[y]);
rc[z]=merge(rc[x],rc[y]);
mx[z]=max(mx[lc[z]],mx[rc[z]]);
return z;
}
inline void build_ST() {
static int c[N],q[N];
for(int i=1;i<=s.tot;i++) c[s.l[i]]++;
for(int i=1;i<=s.len;i++) c[i]+=c[i-1];
for(int i=1;i<=s.tot;i++) q[c[s.l[i]]--]=i;
for(int i=1;i<=s.len;i++) inc(rt[s.pos[i]],1,s.len,i);
for(int i=s.tot;i>=1;i--) if(s.fail[q[i]]) rt[s.fail[q[i]]]=merge(rt[s.fail[q[i]]],rt[q[i]]);
}
inline void solve() {
static int cov[N],len[N];
t.init();
for(int i=1;i<=t.len;i++) len[i]=0;
for(int i=1;i<=t.tot;i++) cov[i]=0;
for(int i=1;i<=t.len;i++) {
int p=t.pos[i];
while(p && !cov[p]) cov[p]=t.l[p], p=t.fail[p];
if(p) len[i]=cov[p];
}
int l,r; scanf("%d%d",&l,&r);
int p=1, mx=0;
#define mn(x) (s.l[s.fail[x]]+1)
for(int i=1;i<=t.len;i++) {
int c=t.ch[i]-'a';
while(p) {
int lst=ask(rt[s.son[p][c]],1,s.len,l,r);
if(lst>=l+mn(s.son[p][c])-1) {
mx=min(mx+1,lst-l+1);
p=s.son[p][c];
break;
} else p=s.fail[p], mx=s.l[p];
}
len[i]=max(len[i],mx);
if(!p) p=1, mx=0;
}
long long ans=0;
for(int i=1;i<=t.len;i++) ans+=i-len[i];
printf("%lld\n",ans);
}
int main() {
s.init(); build_ST();
int T; scanf("%d",&T);
while(T--) solve();
}