[BZOJ4556][Tjoi2016&Heoi2016]字符串 主席树+二分+倍增+后缀自动机

时间:2025-03-25 15:36:43

4556: [Tjoi2016&Heoi2016]字符串

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1215  Solved: 484
[Submit][Status][Discuss]

Description

佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE
O,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公
共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

Input

输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来
m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,
字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n

Output

对于每一次询问,输出答案。

Sample Input

5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4

Sample Output

1
1
2
2
2

HINT

Source

 #include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define maxn 200010
using namespace std;
int n,m;
struct data {
int last,cnt;
int link[maxn],step[maxn],son[maxn][];
int v[maxn],pos[maxn],fa[maxn][],w[maxn];
int s[maxn*][],rt[maxn],t;
void insert(int &k,int l,int r,int x) {
k=++t;
if(l==r) return;
int mid=l+r>>;
if(x<=mid) insert(s[k][],l,mid,x);
else insert(s[k][],mid+,r,x);
}
int merge(int x,int y) {
if(!x||!y) return x+y;
int z=++t;
s[z][]=merge(s[x][],s[y][]);s[z][]=merge(s[x][],s[y][]);
return z;
}
bool query(int x,int l,int r,int L,int R) {
if(!x) return ;
if(L<=l&&R>=r) return ;
int mid=l+r>>;
if (R<=mid) return query(s[x][],l,mid,L,R);
else if(L>mid) return query(s[x][],mid+,r,L,R);
else return query(s[x][],l,mid,L,mid)||query(s[x][],mid+,r,mid+,R);
}
data() {last=cnt=;}
void extend(int x,int id) {
int p=last,np=last=++cnt;step[np]=step[p]+;insert(rt[np],,n,id);w[id]=np;
while(p&&!son[p][x]) son[p][x]=np,p=link[p];
if(!p) link[np]=;
else {
int q=son[p][x];
if(step[q]==step[p]+) link[np]=q;
else {
int nq=++cnt;
memcpy(son[nq],son[q],sizeof(son[q]));
link[nq]=link[q];
link[q]=link[np]=nq;
step[nq]=step[p]+;
while(p&&son[p][x]==q) son[p][x]=nq,p=link[p];
}
}
}
void pre() {
for(int i=;i<=cnt;i++) v[step[i]]++;
for(int i=;i<=cnt;i++) v[i]+=v[i-];
for(int i=cnt;i;i--) pos[v[step[i]]--]=i;
for(int i=cnt;i;i--) {
rt[link[pos[i]]]=merge(rt[link[pos[i]]],rt[pos[i]]);
fa[pos[i]][]=link[pos[i]];
}
for(int j=;j<=;j++) for(int i=;i<=cnt;i++) fa[i][j]=fa[fa[i][j-]][j-];
}
bool check(int mid,int x,int l,int r) {
for(int i=;i>=;i--) if(step[fa[x][i]]>=mid) x=fa[x][i];
return query(rt[x],,n,l,r);
}
}a;
char ch[maxn];
int main() {
scanf("%d%d",&n,&m);
scanf("%s",ch+);reverse(ch+,ch+n+);
for(int i=;i<=n;i++) a.extend(ch[i]-'a',i);
a.pre();
for(int i=;i<=m;i++) {
int a1,b1,c1,d1;scanf("%d%d%d%d",&a1,&b1,&c1,&d1);
a1=n-a1+;b1=n-b1+;c1=n-c1+;d1=n-d1+;
swap(a1,b1);swap(c1,d1);
int l=,r=min(d1-c1+,b1-a1+);
while(l<=r) {
int mid=l+r>>;
if(a.check(mid,a.w[d1],a1+mid-,b1)) l=mid+;
else r=mid-;
}
printf("%d\n",l-);
}
}