终于做完佳媛姐姐系列
后缀数组+RMQ+主席树
本题求的是两段子串中的LCS
当然LCS是可以用LCP求的
首先建立SA
得到a,b,c,d求出rk-c
二分LCS设查询mid
由于求两个串的LCP是求rk1-rk2的min
建立ST表
利用RMQ查出rkc所能覆盖的区间L,R
这个时候很明显出现在L-R就是合法的
那么易得区间版本查询
建立主席树查询节点即可
#include
#include
#include
#include
#include
using namespace std;
const int N=1e6+1000;
char S[N];
int x[N];
int y[N];
int c[N];
int SA[N];
int n,m;
void Get_SA(){
for(int i=1;i<=n;++i)x[i]=S[i];
for(int i=1;i<=n;++i)++c[x[i]];
for(int i=1;i<=m;++i)c[i]+=c[i-1];
for(int i=n;i>=1;i--)SA[c[x[i]]--]=i;
for(int k=1;k<=n;k=k<<1){
int num=0;
for(int i=n-k+1;i<=n;++i)y[++num]=i;
for(int i=1;i<=n;++i)if(SA[i]>k)y[++num]=SA[i]-k;
for(int i=1;i<=m;++i)c[i]=0;
for(int i=1;i<=n;++i)++c[x[i]];
for(int i=1;i<=m;++i)c[i]+=c[i-1];
for(int i=n;i>=1;--i)SA[c[x[y[i]]]--]=y[i],y[i]=0;
swap(x,y);
num=1;
x[SA[1]]=1;
for(int i=2;i<=n;++i)x[SA[i]]=(y[SA[i]]==y[SA[i-1]]&&y[SA[i]+k]==y[SA[i-1]+k])?num:++num;
if(n==num)break;
m=num;
}
}
int rk[N]={};
int height[N]={};
void Get_Height(){
for(int i=1;i<=n;++i)rk[SA[i]]=i;
int k=0;
for(int i=1;i<=n;++i){
if(rk[i]==1)continue;
if(k)k--;
int Id=SA[rk[i]-1];
while(Id+k<=n&&i+k<=n&&S[Id+k]==S[i+k])++k;
height[rk[i]]=k;
}
}
int st[N][20]={};
void Get_RMQ(){
memset(st,0x3f,sizeof(st));
for(int i=1;i<=n;++i){
st[i][0]=height[i];
}
for(int j=1;j<=20;++j)
for(int i=1;i<=n;++i){
if(i+(1<<(j-1))>n)break;
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
}
int lson[N*10]={};
int rson[N*10]={};
int root[N]={};
int sum[N*10]={};
int cnt=0;
void Update(int x,int &y,int l,int r,int pos){
y=++cnt;
lson[y]=lson[x];
rson[y]=rson[x];
sum[y]=sum[x]+1;
if(l==r)return;
int mid=(l+r)/2;
if(pos<=mid)
Update(lson[x],lson[y],l,mid,pos);
else Update(rson[x],rson[y],mid+1,r,pos);
}
int Query(int x,int y,int l,int r,int dl,int dr){
if(dl<=l&&r<=dr){
return sum[y]-sum[x];
}
int mid=(l+r)/2;
int ret=0;
if(dl<=mid)ret+=Query(lson[x],lson[y],l,mid,dl,dr);
if(mid< dr)ret+=Query(rson[x],rson[y],mid+1,r,dl,dr);
return ret;
}
int main(){
int Q;
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
scanf("%d%d",&n,&Q);
scanf("%s",S+1);
m=200;
Get_SA();
Get_Height();
Get_RMQ();
for(int i=1;i<=n;++i)Update(root[i-1],root[i],1,n,rk[i]);
while(Q--){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
int l=1;
int r=min((b-a+1),(d-c+1));
int ans=0;
while(l<=r){
int L,R;
L=R=rk[c];
int mid=(l+r)/2;
for(int i=20;i>=0;i--)if(L-(1<=0&&st[L-(1<=mid)L=L-(1<=0;i--)if(R+(1<=mid)R=R+(1<0)ans=mid,l=mid+1;
else r=mid-1;
}
cout<