实在是高!!!
怕以后看不懂但是也说不太清,就说一些点:

构建出来的的图其实是为了或者说可以看成为了后缀而服务的,回跳边是回跳到了后缀相同的地方。
即:你可以看图中7号点他的回跳边是3,你再从3往上走到0点就会发现这条路径只是从7回到零点的后缀。

然后查找过程:
看图有一次沿着5,6,7找即s,h,e然后根据回跳边跳转。
那么转移边有什么用呢,图里也说了主串沿着树边或者转移边走。
举个例子:串yasherhshe,遍历到yashe后,下一个字符是r,怎么走到r呢,他其实是在原来遍历e的时候i=7,然后在7的地方走转移边到r。
这样子就能直接找到后缀相同同时结尾为r的位置。
附上代码(直接copy董晓老师的):
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n;
char str[1000010];
int ch[N][26],cnt[N],idx;
int ne[N];
void insert(char *s){//注意这只是创建单个字符串的字典树
int p=0;
for(int i=0;s[i];i++){
int j=s[i]-'a';
if(!ch[p][j])ch[p][j]=++idx;//若子节点不存在那么就添加这个节点
p=ch[p][j];
}
cnt[p]++;
}
void build(){
queue<int>q;
for(int i=0;i<26;i++){
if(ch[0][i])q.push(ch[0][i]);
}
while(q.size()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
int v=ch[u][i];
if(v)ne[v]=ch[ne[u]][i],q.push(v);//儿子存在,创建回跳边
else ch[u][i]=ch[ne[u]][i];//儿子不存在建立转移边
}
}
}
int query(char *s){
int ans=0;
for(int k=0,i=0;s[k];k++){
i=ch[i][s[k]-'a'];
for(int j=i;j&&~cnt[j];j=ne[j])
ans+=cnt[j],cnt[j]=-1;
}
return ans;
}
int main(){
cin>>n;
for(int i=0;i<n;i++)
cin>>str,insert(str);
build();
cin>>str;
cout<<query(str)<<endl;
return 0;
}