二分答案,(具体可见http://blog.csdn.net/neither_nor/article/details/51669114),然后就是判定问题,sa和sam都可以做,用sam写了一下,先用sam建后缀树,然后用主席树维护right集合就好了,每次判断把对应节点倍增到深度为mid的点,然后看一下他的子树里有没有right在对应区间的点就好了。
(前几天用sa写了一下,bz能A,洛谷一直WA,有空重构吧。。。)
#include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> #include<vector> using namespace std; const int maxn=200010,maxm=4000010; int a,b,c,d,t,pos[maxn],cnt=1,cur,fa[maxn],ch[maxn][26],dis[maxn],n,m,tot; char s[maxn]; int add(int c,int p){ cur=++cnt;dis[cur]=dis[p]+1; for(;p&&!ch[p][c];p=fa[p])ch[p][c]=cur; if(!p)fa[cur]=1; else{ int q=ch[p][c]; if(dis[q]==dis[p]+1)fa[cur]=q; else{ int nt=++cnt;dis[nt]=dis[p]+1; memcpy(ch[nt],ch[q],sizeof(ch[0])); fa[nt]=fa[q];fa[q]=fa[cur]=nt; for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nt; } } return cur; } vector<int>tong[maxn]; int root[maxn],siz[maxn],tim,last[maxn*2],pre[maxn*2],other[maxn*2],f[maxn][25],dfn[maxn],from[maxn]; void insert(int x,int y){++t;pre[t]=last[x];last[x]=t;other[t]=y;} void dfs(int x){ siz[x]=1;dfn[x]=++tim;from[tim]=x; for(int i=last[x];i;i=pre[i]){ int v=other[i]; f[v][0]=x;dfs(v); siz[x]+=siz[v]; } } int jump(int x,int y){ for(int i=20;i>=0;--i){ if(dis[f[x][i]]>=y)x=f[x][i]; } return x; } struct node{ int l,r,v; }tr[maxm]; void build(int pos,int l,int r,int &x){ ++tot;tr[tot]=tr[x];x=tot;++tr[x].v; if(l==r)return; int mid=l+r>>1; if(pos<=mid)build(pos,l,mid,tr[x].l); else build(pos,mid+1,r,tr[x].r); } int qs(int i,int j,int l,int r,int L,int R){ if(r<L||l>R||r<l)return 0; if(l>=L&&r<=R)return tr[j].v-tr[i].v; int mid=l+r>>1; return qs(tr[i].l,tr[j].l,l,mid,L,R)+qs(tr[i].r,tr[j].r,mid+1,r,L,R); } int pd(int mid){ int op=jump(pos[c],mid); return qs(root[dfn[op]-1],root[dfn[op]+siz[op]-1],1,n,a,b-mid+1); } int main(){ //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); int tmp=1; cin>>n>>m; scanf("%s",s+1); for(int i=n;i>=1;--i){ tmp=add(s[i]-'a',tmp); pos[i]=tmp; tong[pos[i]].push_back(i); } for(int i=2;i<=cnt;++i)insert(fa[i],i);dfs(1); for(int j=1;j<=20;++j) for(int i=1;i<=cnt;++i){ f[i][j]=f[f[i][j-1]][j-1]; } for(int i=1;i<=tim;++i){ int siz=tong[from[i]].size();root[i]=root[i-1]; for(int j=0;j<siz;++j){ build(tong[from[i]][j],1,n,root[i]); } } for(int i=1;i<=m;++i){ scanf("%d%d%d%d",&a,&b,&c,&d); int l=1,r=min(d-c+1,b-a+1),ans=0; while(l<=r){ int mid=l+r>>1; if(pd(mid))ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); } //fclose(stdin); //fclose(stdout); //system("pause"); return 0; } /* 50 1 pnzogoobycwczqfrbylxuwkgmnzlekbcakviijcrjahthagkcn 20 47 8 50 */