BZOJ3756: Pty的字符串
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3756
3756: Pty的字符串
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 152 Solved: 42
[Submit][Status][Discuss]
Description
在神秘的东方有一棵奇葩的树,它有一个固定的根节点(编号为1)。树的每条边上都是一个字符,字符为a,b,c中的一个,你可以从树上的任意一个点出发,然后沿着远离根的边往下行走,在任意一个节点停止,将你经过的边的字符依次写下来,就能得到一个字符串,例如:
在这棵树中我们能够得到的字符串是:
c, cb, ca, a, b, a
现在pty得到了一棵树和一个字符串S。如果S的一个子串[l,r]和树上某条路径所得到的字符串完全相同,则我们称这个子串和该路径匹配。现在pty想知道,S的所有子串和树上的所有路径的匹配总数是多少?
Input
第一行:n
接下来n-1行,每行一个整数fa, 一个字符c,字符和整数之间用一个空格隔开
第i行fa代表第i号节点的父亲,c表示第i号节点和fa的连边的字符
最后一行为字符串S
Output
输出共一行,表示匹配总数
Sample Input
5
1 c
2 b
1 a
2 a
cba
1 c
2 b
1 a
2 a
cba
Sample Output
5
【样例说明】
单个字符匹配的对数为4对,两个字符匹配的对数为1对:cb
【样例说明】
单个字符匹配的对数为4对,两个字符匹配的对数为1对:cb
HINT
【数据规模】
N<=800000 树的最大深度<=800000
把trie树建成后缀自动机,dp一下,把s串在后缀自动机匹配的同时更新答案就好了。注意开longlong。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define inf 1<<30 5 #define maxn 800005 6 using namespace std; 7 int n,m,head,tail,tot,last,par[maxn*2],go[maxn*2][3],val[maxn*2],size[maxn*2],q[maxn*2],d[maxn*2],fin[maxn]; 8 long long f[maxn*2],ans; 9 char s[maxn*10]; 10 int newnode(int x){val[++tot]=val[x]+1;return tot;} 11 void extend(int x){ 12 int p=last,np=newnode(p); size[np]=1; 13 while(p&&!go[p][x]) go[p][x]=np,p=par[p]; 14 if(!p) par[np]=1; 15 else{ 16 int q=go[p][x]; 17 if(val[q]==val[p]+1) par[np]=q; 18 else{ 19 int nq=newnode(p); 20 memcpy(go[nq],go[q],sizeof(go[q])); 21 par[nq]=par[q]; par[q]=par[np]=nq; 22 while(p&&go[p][x]==q) go[p][x]=nq,p=par[p]; 23 } 24 } 25 last=np; 26 } 27 int main(){ 28 scanf("%d",&n); 29 int x; char y; 30 last=tot=fin[1]=1; 31 for(int i=2;i<=n;i++){ 32 scanf("%d",&x); for(y=getchar();y==' ';y=getchar()); 33 last=fin[x]; extend(y-'a'); fin[i]=last; 34 } 35 for(int i=1;i<=tot;i++) d[par[i]]++; 36 for(int i=1;i<=tot;i++) if(d[i]==0) q[++tail]=i; 37 while(head<tail){ 38 x=q[++head]; 39 size[par[x]]+=size[x]; 40 if((--d[par[x]])==0) q[++tail]=par[x]; 41 } 42 for(int i=1;i<=tail;i++) f[i]=1LL*(val[i]-val[par[i]])*size[i]; 43 for(int i=tail;i;i--) f[q[i]]+=f[par[q[i]]]; 44 scanf("%s",s); m=strlen(s); 45 for(int i=0,z=1,pp=0;i<m;i++){ 46 int w=s[i]-'a'; 47 while(z&&!go[z][w]) z=par[z],pp=val[z]; 48 if(!z) z=1,pp=0; 49 else pp++,z=go[z][w],ans+=f[par[z]]+1LL*(pp-val[par[z]])*size[z]; 50 } 51 printf("%lld\n",ans); 52 return 0; 53 }