【BZOJ4556】【TJOI2016&HeOI2016】—字符串(后缀数组+主席树+ST表)
先建出,考虑二分串的长度,判断可行
显然和这个串的的那些相连的一块都是满足的
那我们就只需要查询是否有串在~的子串内
对建一颗主席树,区间查询就可以了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=200005;
const int Log=21;
int n,m,q,a[N],lg[N];
char s[N];
#define mid ((l+r)>>1)
struct President_Tree{
int tot,rt[N],lc[N<<5],rc[N<<5],sum[N<<5];
void insert(int &now,int u,int l,int r,int p){
now=++tot,lc[now]=lc[u],rc[now]=rc[u],sum[now]=sum[u]+1;
if(l==r)return;
if(p<=mid)insert(lc[now],lc[u],l,mid,p);
else insert(rc[now],rc[u],mid+1,r,p);
}
int query(int r1,int r2,int l,int r,int st,int des){
if(st<=l&&r<=des)return sum[r2]-sum[r1];
int res=0;
if(st<=mid)res+=query(lc[r1],lc[r2],l,mid,st,des);
if(mid<des)res+=query(rc[r1],rc[r2],mid+1,r,st,des);
return res;
}
}Seg;
#undef mid
struct Sa{
int rk[N],sa[N],sa2[N],cnt[N],ht[N],st[Log][N<<1];
inline void bucket_sort(){
for(int i=1;i<=m;i++)cnt[i]=0;
for(int i=1;i<=n;i++)++cnt[rk[sa2[i]]];
for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--)sa[cnt[rk[sa2[i]]]--]=sa2[i];
}
inline void buildsa(){
m=50;
for(int i=1;i<=n;i++)rk[i]=a[i],sa2[i]=i;
bucket_sort();
for(int i=1,pos=0;i<=n&&pos<n;i<<=1){
pos=0;
for(int j=n-i+1;j<=n;j++)sa2[++pos]=j;
for(int j=1;j<=n;j++)if(sa[j]>i)sa2[++pos]=sa[j]-i;
bucket_sort();
swap(rk,sa2);
rk[sa[1]]=1,pos=1;
for(int j=2;j<=n;j++)
rk[sa[j]]=((sa2[sa[j]]==sa2[sa[j-1]])&&(sa2[sa[j]+i]==sa2[sa[j-1]+i])?pos:++pos);
m=pos;
}
for(int i=1;i<=n;i++)rk[sa[i]]=i;
for(int i=1,k=0,j;i<=n;ht[rk[i++]]=k){
for(k?k--:0,j=sa[rk[i]-1];a[i+k]==a[j+k];k++);
}
}
inline void init(){
for(int i=1;i<=n;i++)st[0][i]=ht[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[j][i]=min(st[j-1][i],st[j-1][i+(1<<(j-1))]);
}
}T;
int main(){
n=read(),q=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)a[i]=s[i]-'a'+1;
T.buildsa(),T.init();
for(int i=1;i<=n;i++)Seg.insert(Seg.rt[i],Seg.rt[i-1],1,n,T.rk[i]);
while(q--){
int A=read(),B=read(),C=read(),D=read();
int ans=0,l=0,r=min(B-A,D-C)+1;
while(l<=r){
int mid=(l+r)>>1;
int st=T.rk[C],des=T.rk[C];
for(int i=20;~i;i--)if(st>=(1<<i)&&T.st[i][st-(1<<i)+1]>=mid)st-=(1<<i);
for(int i=20;~i;i--)if(des+(1<<i)<=n&&T.st[i][des+1]>=mid)des+=(1<<i);
if(Seg.query(Seg.rt[A-1],Seg.rt[B-mid+1],1,n,st,des)>0)ans=mid,l=mid+1;
else r=mid-1;
}
cout<<ans<<'\n';
}
}