【BZOJ4556】【TJOI2016&HeOI2016】—字符串(后缀数组+主席树+ST表)

传送门

先建出SaSa,考虑二分串的长度,判断可行

显然和CC这个串的lcp>=midlcp>=mid的那些rankrank相连的一块都是满足的

那我们就只需要查询是否有串在aa~bb的子串内
rkrk建一颗主席树,区间查询就可以了

#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';
    }
}
posted @ 2019-02-28 18:55  Stargazer_cykoi  阅读(126)  评论(0编辑  收藏  举报