题目描述

在神秘的东方有一棵奇葩的树,它有一个固定的根节点(编号为1)。树的每条边上都是一个字符,字符为a,b,c中的一个,你可以从树上的任意一个点出发,然后沿着远离根的边往下行走,在任意一个节点停止,将你经过的边的字符依次写下来,就能得到一个字符串,例如:

在这棵树中我们能够得到的字符串是:

c, cb, ca, a, b, a

现在pty得到了一棵树和一个字符串S。如果S的一个子串[l,r]和树上某条路径所得到的字符串完全相同,则我们称这个子串和该路径匹配。现在pty想知道,S的所有子串和树上的所有路径的匹配总数是多少?

输入格式

第一行:n

接下来n-1行,每行一个整数fa, 一个字符c,字符和整数之间用一个空格隔开

第i行fa代表第i号节点的父亲,c表示第i号节点和fa的连边的字符

最后一行为字符串S

输出格式

输出共一行,表示匹配总数,因为评测系统暂未确定,所以C/C++选手请使用cout输出。

样例

样例输入

5
1 c
2 b
1 a
2 a
cba

样例输出

5

数据范围与提示

【样例说明】

单个字符匹配的对数为4对,两个字符匹配的对数为1对:cb


solution

 
广义后缀自动机
其实是在trie树上建。
具体看
记录 val[i] 表示i这个状态所代表的所有串的出现次数和
val=(max-min)*right
记sum为i到根的val之和。
做匹配的时候,我们考虑新加入一个字符。
假设这个字符的匹配点是i,之前匹配长度为len。
那么这个字符的答案就是(len-s[fa].max)*ri[i]+s[fa].sum.
也就是该字符串在这个点的匹配长度,加上父亲点的sum,也就是以这个字符结尾的其他后缀的贡献。
 格式化代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 800005
#define ll long long
using namespace std;
int n,id[maxn],rt=,cnt=,la=,a[maxn];
struct node{
int nex[],par,Max,ri;
ll val,sum;
}s[maxn*];
char ch[maxn*];
ll tax[maxn];
void ins(int fa,int c,int i){ int np=++cnt,p=id[fa];s[np].ri=;
//cout<<i<<' '<<c<<' '<<p<<endl;
s[np].Max=s[la].Max+;id[i]=la=np;//这里还不是很懂为什么是la for(;p&&!s[p].nex[c];p=s[p].par)s[p].nex[c]=np;
if(!p)s[np].par=rt;
else {
int q=s[p].nex[c];
if(s[q].Max==s[p].Max+)s[np].par=q;
else {
int nq=++cnt;
for(int i=;i<;i++)s[nq].nex[i]=s[q].nex[i];
s[nq].par=s[q].par;s[nq].Max=s[p].Max+;
s[q].par=s[np].par=nq;
for(;s[p].nex[c]==q;p=s[p].par)s[p].nex[c]=nq;
}
}
}
void Calc(){
for(int i=;i<=cnt;i++)tax[s[i].Max]++;
for(int i=;i<=cnt;i++)tax[i]+=tax[i-];
for(int i=;i<=cnt;i++)a[tax[s[i].Max]--]=i;
for(int i=cnt;i>=;i--){
int k=a[i],f=s[k].par;
s[f].ri+=s[k].ri;
s[k].val=s[k].ri*(s[k].Max-s[f].Max);
}
for(int i=;i<=cnt;i++){
int k=a[i];
s[k].sum=s[k].val+s[s[k].par].sum;
}
}
int main(){
cin>>n;id[]=;
for(int i=,fa;i<=n;i++){
char c;scanf("%d %c",&fa,&c);
ins(fa,c-'a',i);
}
Calc();
scanf("%s",ch);int l=strlen(ch),len=;
int p=rt;ll ans=;
for(int i=;i<l;i++){
for(;!s[p].nex[ch[i]-'a']&&p;p=s[p].par,len=s[p].Max);
if(!p)p=rt,len=;
else {
p=s[p].nex[ch[i]-'a'];len++;
int f=s[p].par;
ans=ans+s[f].sum+(len-s[f].Max)*s[p].ri;
}
}
cout<<ans<<endl;
return ;
}

Pty的字符串(string)的更多相关文章

  1. javascript类型系统——字符串String类型

    × 目录 [1]定义 [2]引号 [3]反斜线[4]特点[5]转字符串 前面的话 javascript没有表示单个字符的字符型,只有字符串String类型,字符型相当于仅包含一个字符的字符串 字符串S ...

  2. C# 字符串string类型转换成DateTime类型 或者 string转换成DateTime?(字符串转换成可空日期类型)

    在c#中,string类型转换成DateTime类型是经常用到的,作为基本的知识,这里在此做个小结.一般来说可以使用多种方法进行转换,最常用的就是使用Convert.ToDateTime(string ...

  3. Java常量字符串String理解

    Java常量字符串String理解 以前关于String的理解仅限于三点:1.String 是final类,不可继承2.String 类比较字符串相等时时不能用“ == ”,只能用  "eq ...

  4. 字符串string类型转换成DateTime或DateTime?类型

    常用的Convert.ToDateTime方法 //将含有正确日期格式的string类型转换成DateTime类型 string strDate = "2014-08-01"; D ...

  5. Javascript基础系列之(三)数据类型 (字符串 String)

    javascript一共有9种数据类型 字符串 String 数值型 Number 布尔型 Boolean 未定义 Undefine 空值 Null 对象 Object 引用Refernce 列表型 ...

  6. Java基础——数组应用之字符串String类

    字符串String的使用 Java字符串就是Unicode字符序列,例如串“Java”就是4个Unicode字符J,a,v,a组成的. Java中没有内置的字符串类型,而是在标准Java类库中提供了一 ...

  7. java中字符串String 转 int(转)

    java中字符串String 转 int String -> int s="12345"; int i; 第一种方法:i=Integer.parseInt(s); 第二种方法 ...

  8. 字符串String类

    1. String类是一个密封类.用关键字sealed修饰: 2. 字符串的两个特性:     ·不可变性:string类型变量,一旦声明就表明它是不会被改变的.因此,string中的方法对strin ...

  9. 字符串string和内存流MemoryStream及比特数组byte[]互转

    原文:字符串string和内存流MemoryStream及比特数组byte[]互转   字符串string和内存流MemoryStream及比特数组byte[]互转比较 定义string变量为str, ...

随机推荐

  1. 经典sql语句汇总

    1,某条数据放首位,其他倒序并分页 select * from Student order by( case     when id='2'  then 1 ELSE 4 END),id desc l ...

  2. Servlet学习笔记01——什么是servlet?

    1.什么是Servlet? sun公司制订的一种用来扩展web服务器功能的组件规范. (1)扩展web服务器功能 早期的web服务器(apache web server,iis) 只能处理静态资源的请 ...

  3. django+xadmin在线教育平台(十四)

    7-1 django templates模板继承1 机构可以筛选类别 机构可以根据所在地区进行分类 右侧我要学习功能: form表单提交 右下:授课机构排名 页面头部与底部为全局头和全局底部. Dja ...

  4. Java源码解析——Java IO包

    一.基础知识: 1. Java IO一般包含两个部分:1)java.io包中阻塞型IO:2)java.nio包中的非阻塞型IO,通常称为New IO.这里只考虑到java.io包中堵塞型IO: 2. ...

  5. mysql悲观锁与乐观锁

    简介 数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 用途 乐观锁和悲观锁是并发控制主要采用的技术手段.无论是悲观 ...

  6. Python学习笔记:logging(日志处理)

    在一个软件中,日志是可以说必不可少的一个组成部分,通常会在定位客户问题或者记录软件使用情况等场景中会用到.logging模板块是Python的一个内置标准库,用于实现对日志的控制输出,对于平常的日志输 ...

  7. Android 中的一些特殊目录与文件

    用作命令的二进制文件位于/system/bin/与/system/xbin/下 应用数据位于/data/data/, 原始安装文件位于/data/app/(Play商店中非免费应用位于/data/ap ...

  8. 剑指Offer - 九度1384 - 二维数组中的查找

    剑指Offer - 九度1384 - 二维数组中的查找2013-11-23 23:23 题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个 ...

  9. Lazarus教程 中文版后续给出

    市面上有介绍Delphi的书籍(近来Delphi的书也是越来越少了),但没有一本系统的介绍Lazarus的书,这本书是网上的仅有的一本Lazarus教程,目前全部是英文,不过我已经着手开始翻译,争取尽 ...

  10. 【Binary Tree Right Side View 】cpp

    题目: Given a binary tree, imagine yourself standing on the right side of it, return the values of the ...