给出一个字符串S和m个询问。
每个询问有两个数l,r,要求以结尾为第l位和第r位的子串中,有多少个是原串的前缀,以及当中最长的子串的长度。
|S|<=30000,m<=100000
时间限制 1s
空间限制 256M
先做一遍kmp得到数组P,然后令字符串的每一位对应一个点,构出一棵树,满足P[i]是i的父亲,这样最长长度就是l、r的lca的编号,子串数量就是lca的深度。
#include
#include
#include
#define maxn 30006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll ding=1e8+7;
struct poi
{
int x;
poi *nex;
} *a[maxn];
int i,n,len,l,r,s,ans,p[maxn],dep[maxn],fa[maxn][27];
char st[maxn];
void link(int x,int y)
{
poi *p=new poi;
p->x=y;
p->nex=a[x];
a[x]=p;
return;
}
void dfs(int x)
{
poi *p=new poi;
for(p=a[x];p;p=p->nex)
if (p->x!=fa[x][0])
{
dep[p->x]=dep[x]+1;
fa[p->x][0]=x;
dfs(p->x);
}
return;
}
void pre()
{
int i,j=0;
p[1]=0;
len=strlen(st+1);
fr(i,2,len)
{
while (j && st[i]!=st[j+1]) j=p[j];
if (st[i]==st[j+1]) j++;
p[i]=j;
}
fr(i,1,len) link(i,p[i]),link(p[i],i);
dfs(0);
fr(j,1,26)
fr(i,1,len)
fa[i][j]=fa[fa[i][j-1]][j-1];
return;
}
int getlca(int x,int y)
{
if (dep[y]>dep[x]) swap(x,y);
int i,d=dep[x]-dep[y];
fr(i,0,26)
if (d & (1 << i))
x=fa[x][i];
if (x==y) return x;
for(i=26;i>=0;i--)
if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main()
{
scanf("%s",st+1);
pre();
scanf("%d",&n);
fr(i,1,n)
{
scanf("%d%d",&l,&r);
int lca=getlca(l,r);
printf("%d %d\n",dep[lca],lca);
}
return 0;
}