正题
题目大意
一个字符串SSS,给出若干个l,rl,rl,r
求SSS以lll和rrr结尾的前缀一个公共后缀且它是SSS的前缀的子串。
求有多少和最长的那个的长度
解题思路
首先后缀前缀很容易想到KMPKMPKMP,我们先处理出nextnextnext数组
然后从(l,r)(l,r)(l,r)开始让lll和rrr跳到它们的nextnextnext的位置知道两个相等就好了
但是这样会TTT飞,那么我们发现可以将问题转换
每次将(nexti,i)(next_i,i)(nexti,i)连边,就变成了一棵树,然后求LCALCALCA和它的深度就好了
codecodecode
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define N 31000
using namespace std;
struct line{int to,next,w;
}a[N*5];
int tot,n,m,x,y,ls[N],dep[N],f[N][30],dis[N][30],t,next[N];
char s[N];
queue<int> q;
inline int readn()
{int X=0,w=0; char c=0;while(c<'0'||c>'9') {w|=c=='-';c=getchar();}while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();return w?-X:X;
}
inline void addl(int x,int y,int w)
{a[++tot].to=y;a[tot].next=ls[x];a[tot].w=w;ls[x]=tot;
}
inline void bfs(int s)
{q.push(s);dep[s]=1;while(!q.empty()){int x=q.front();q.pop();for (int i=ls[x];i;i=a[i].next){int y=a[i].to;if (dep[y]) continue;q.push(y);f[y][0]=x;dep[y]=dep[x]+1;dis[y][0]=a[i].w;}}t=(int)(log(n)/log(2))+1;for (int j=1;j<=t;j++){for (int i=0;i<=n;i++){f[i][j]=f[f[i][j-1]][j-1];dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);}}
}
inline int LCA(int x,int y)
{if (dep[x]>dep[y]) swap(x,y);for (int i=t;i>=0;i--)if (dep[f[y][i]]>=dep[x]) y=f[y][i];if (x==y) return x;for (int i=t;i>=0;i--)if (f[y][i]!=f[x][i]) {x=f[x][i];y=f[y][i];}return f[x][0];
}
void Kmp_build()
{for(int i=2,j=0;i<=n;i++){while(j&&(s[i]!=s[j+1])) j=next[j];j+=(s[i]==s[j+1]);next[i]=j;}for(int i=1;i<=n;i++)addl(next[i],i,1);
}
int main()
{scanf("%s",s+1);n=strlen(s+1);Kmp_build();bfs(0);scanf("%d",&m);for(int i=1;i<=m;i++){int l,r,ans;scanf("%d%d",&l,&r);ans=LCA(l,r);printf("%d %d\n",dep[ans]-1,ans);}
}