Description

新日暮里中,比冲是一位博学的哲学教授。由于最近要帮学生准备考试,他决定弄个提纲给学生。然而同事van不服气,觉得这样学生就没有了自我思考,便在提纲中添加废话。
比冲很无奈,他想找回原稿。我们把现在的提纲看成是一个字符串S。他知道van只会在原稿结尾添加语句,也就是说,原稿是S的前缀。
现在比冲有m个询问,以此来找出原稿。每次给出两个位置l,r,问以l与r结尾的字符串中,有多少个字符串符合原稿的性质,最长的有多长。

Solution

表示想向出题人寄刀片,这个题意讲的是什么啊。
看到题解才明白题意。
题意就是说:所有的合法串满足是s的前缀,1~l的后缀,1~r的后缀。
这个不是很显然的在kmp上倍增吗,出题人坑我啊!!!!!!
kmp的p数组p[i]就表示以i结尾的后缀与整串的前缀最大匹配长度,那么从l和r同时向前跳到第一个公共节点,然后再访问公共节点的深度就可以了。
就像在一棵树上倍增一样。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=100007;
int i,j,k,l,t,n,m,ans;
int p[maxn],f[maxn][21],deep[maxn];
int first[maxn*2],next[maxn*2],last[maxn*2],num;
char s[maxn];
void add(int x,int y){
last[++num]=y;next[num]=first[x];first[x]=num;
}
void dfs(int x,int y){
int i;
deep[x]=deep[y]+1;f[x][0]=y;
rep(i,x){
if(last[i]!=y){
dfs(last[i],x);
}
}
}
int lca(int x,int y){
int i;if(deep[x]<deep[y])swap(x,y);
fod(i,20,0)if(deep[f[x][i]]>deep[y])x=f[x][i];
if(deep[x]!=deep[y])x=f[x][0];
fod(i,20,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
if(x!=y)return f[x][0];return x;
}
int main(){
scanf("%s",s+1);n=strlen(s+1);
fo(i,2,n){
while(j&&s[j+1]!=s[i])j=p[j];
if(s[j+1]==s[i])j++;
add(j,i);
p[i]=j;
// f[j][0]=i;
}
add(0,1);
dfs(0,0);
fo(j,1,20)fo(i,1,n)f[i][j]=f[f[i][j-1]][j-1];
scanf("%d",&m);
fo(i,1,m){
scanf("%d%d",&k,&l);
t=lca(k,l);
printf("%d %d\n",deep[t]-1,t);
}
}