显然的贪心就是尽可能取位置靠前的点
那么问题转化成了维护另一个子串的 (endpos) 在这个子串的出现位置
按照古老的套路就是把一个建出来自动机另一个跑匹配
如果 (l_{ed[r]}<r-l+1) 那么答案就是 (0)
反之考虑当前的点的在 ([tl,tr]) 中所有的 (endpos)
查询的话复杂度是 (frac{len_1}{len_2} imes log_n)
数据大的时候显然能过,但是数据小的时候会完蛋
那么考虑重新维护一个 (f_{len,i,j}) 表示当前字符串是 (S[i,i+len-1]) ,后面的 (2^j) 的字符串的位置,同时记录 (sum_{len,i,j}) 为所有的 (pos) 之和
每个询问倍增跳出来所有的位置和求和即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define reg register
#define ull unsigned long long
namespace yspm{
inline int read(){
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=1e5+10,M=N<<1,SZ=M*40;
int son[M][26],bz[M][20],len[M],tot=1,las=1,fa[M],sum[SZ],ls[SZ],rs[SZ],num,rt[M],n;
char s[N],t[N];
inline void push_up(int x){return sum[x]=sum[ls[x]]+sum[rs[x]],void();}
inline void upd(int &p,int l,int r,int pos){
if(!p) p=++num; if(l==r) return sum[p]=1,void();
int mid=(l+r)>>1; if(pos<=mid) upd(ls[p],l,mid,pos); else upd(rs[p],mid+1,r,pos);
return push_up(p);
}
inline int merge(int x,int y,int l,int r){
if(!x||!y) return x+y; int p=++num;
if(l==r) return sum[p]=sum[x]|sum[y],p;
int mid=(l+r)>>1; ls[p]=merge(ls[x],ls[y],l,mid); rs[p]=merge(rs[x],rs[y],mid+1,r);
return push_up(p),p;
}
inline void extend(int x,int id){
int tmp=las,np=las=++tot; len[np]=len[tmp]+1; upd(rt[np],1,n,id);
while(!son[tmp][x]) son[tmp][x]=np,tmp=fa[tmp];
if(!tmp) return fa[np]=1,void();
int q=son[tmp][x]; if(len[q]==len[tmp]+1) return fa[np]=q,void();
int clone=++tot; len[clone]=len[tmp]+1; for(reg int i=0;i<26;++i) son[clone][i]=son[q][i];
fa[clone]=fa[q]; fa[q]=fa[np]=clone; while(son[tmp][x]==q) son[tmp][x]=clone,tmp=fa[tmp];
return ;
}
struct edge{int to,nxt;}e[M<<1];
int head[M],cnt;
inline void add(int u,int v){
e[++cnt].to=v; e[cnt].nxt=head[u];
return head[u]=cnt,void();
}
inline void dfs(int x){
for(reg int i=1;i<=19;++i) bz[x][i]=bz[bz[x][i-1]][i-1];
for(reg int i=head[x];i;i=e[i].nxt){
bz[e[i].to][0]=x; dfs(e[i].to);
rt[x]=merge(rt[x],rt[e[i].to],1,n);
}return ;
}
int ped[N],led[N];
ll ans[N],k;
ull hs[N],bas=13331,p[N];
inline int findpos(int l,int r){
reg int now=ped[r]; for(reg int i=19;~i;--i) if(len[bz[now][i]]>=r-l+1) now=bz[now][i];
return now;
}
inline int findfir(reg int p,reg int l,reg int r,reg int st,reg int ed){
if(!p) return -1; if(l==r) return l;
reg int mid=(l+r)>>1,res=-1;
if(st<=mid) res=findfir(ls[p],l,mid,st,ed);
if(res!=-1) return res;
if(ed>mid) res=findfir(rs[p],mid+1,r,st,ed);
return res;
}
unordered_map<ull,vector<int> > mp;
inline ull calc(reg int l,reg int r){return hs[r]-hs[l-1]*p[r-l+1];}
struct node{
int id,pos,st,ed;
node(){}
node(reg int xx,reg int yy,reg int ww,reg int zz){id=xx; st=yy; ed=ww; pos=zz; return ;}
};
struct nd{
int pos,ct;
ll sum;
nd(){}
nd(reg int xx,reg int yy,reg int zz){pos=xx; sum=yy; ct=zz;}
nd operator+(const nd &a)const{return nd(a.pos,sum+a.sum,ct+a.ct);}
}nxt[N][20];
vector<node> q[60];
vector<int> tmp;
signed main(){
n=read(); k=read(); scanf("%s%s",s+1,t+1);
for(reg int i=1;i<=n;++i) extend(s[i]-'a',i);
for(reg int i=1;i<=tot;++i) add(fa[i],i); dfs(1);
int now=1,nl=0;
for(reg int i=1;i<=n;++i){
if(son[now][t[i]-'a']) now=son[now][t[i]-'a'],nl++;
else{
while(!son[now][t[i]-'a']&&now) now=fa[now];
if(!now) now=1,nl=0;
else nl=len[now]+1,now=son[now][t[i]-'a'];
} ped[i]=now; led[i]=nl;
}
reg int l1,r1,l2,r2,Q=read(); for(reg int i=1;i<=Q;++i){
l1=read(),r1=read(),l2=read(),r2=read();
if(led[r2]<r2-l2+1||r1-l1+1<l2-r2+1){ans[i]=0; continue;}
now=findpos(l2,r2);
if(r2-l2+1>50){
reg ll res=0; reg int p=findfir(rt[now],1,n,l1+(r2-l2+1)-1,r1);
if(p==-1){ans[i]=0; continue;}
res+=k-(p-(r2-l2+1)+1); p+=r2-l2+1;
while(p<=r1&&p!=-1){
p=findfir(rt[now],1,n,p,r1);
if(p!=-1) res+=k-(p-(r2-l2+1)+1),p+=r2-l2+1;
} ans[i]=res;
}else q[r2-l2+1].push_back(node(i,l1,r1,now));
} p[0]=1;
for(reg int i=1;i<=n;++i) p[i]=p[i-1]*bas,hs[i]=hs[i-1]*bas+s[i];
for(reg int len=1;len<=50;++len){
if(!q[len].size()) continue;
mp.clear();
for(reg int i=len;i<=n;++i){
ull res=hs[i]-hs[i-len]*p[len];
nxt[i][0]=(nd){0,i-len+1,1};
if(mp.count(res)){
reg int r=-1;
for(reg int j=mp[res].size()-1;~j;--j){
if(mp[res][j]<=i-len){r=j;break;}
}
while(r>=0) if(nxt[mp[res][r]][0].pos==0) nxt[mp[res][r]][0].pos=i,--r; else break;
}mp[res].push_back(i);
}
for(reg int i=n;i>=len;--i){
for(reg int j=1;nxt[nxt[i][j-1].pos][j-1].pos;++j) nxt[i][j]=nxt[i][j-1]+nxt[nxt[i][j-1].pos][j-1];
}
for(auto p:q[len]){
reg int st=findfir(rt[p.pos],1,n,p.st+len-1,p.ed);
if(st==-1){ans[p.id]=0;continue;}
reg ll s=0,c=0;
for(reg int i=19;~i;--i){
if(nxt[st][i].pos&&nxt[st][i].pos<=p.ed){
s+=nxt[st][i].sum,c+=nxt[st][i].ct;
st=nxt[st][i].pos;
}
} c++; s+=st-len+1;
ans[p.id]=1ll*k*c-s;
}
for(reg int i=len;i<=n;++i) memset(nxt[i],0,sizeof(nxt[i]));
}
for(reg int i=1;i<=Q;++i) printf("%lld
",ans[i]);
return 0;
}
}
signed main(){return yspm::main();}