bzoj3756pty的字符串(后缀自动机+计数)
题目描述

题解
我们可以先对trie树建出广义SAM,然后维护一下right集合大小(注意right集合在广义SAM上的维护方式)。
然后把匹配穿往广义SAM上匹配,假设现在匹配到了x节点,那么x的所有祖先后可以被匹配上,那么一个节点的贡献即为r[x]*(l[x]-l[fa[x]])。
维护这玩意的和就好了,最下面的节点特判一下。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1600002
#define M 8000002
using namespace std;
typedef long long ll;
char c[],s[M];
int cnt,n,father,pa[N],len,tong[N],rnk[N];
ll sum[N],ans;
int l[N],ch[N][],fa[N],r[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline int ins(int last,int x){
int p=last;
if(ch[p][x]){
int q=ch[p][x];
if(l[p]+==l[q]){r[q]++;return q;}
else{
int nq=++cnt;l[nq]=l[p]+;r[nq]=;//care!!!!!!!!!!!!!!!
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
return nq;
}
}
else{
int np=++cnt;l[np]=l[p]+;r[np]=;
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
if(!p)fa[np]=;
else{
int q=ch[p][x];
if(l[p]+==l[q])fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
return np;
}
}
int main(){
n=rd();cnt=;pa[]=;
for(int i=;i<=n;++i){
father=rd();scanf("%s",c);
pa[i]=ins(pa[father],c[]-'a');
}
scanf("%s",s+);len=strlen(s+);
for(int i=;i<=cnt;++i)tong[l[i]]++;
for(int i=;i<=n;++i)tong[i]+=tong[i-];
for(int i=;i<=cnt;++i)rnk[tong[l[i]]--]=i;
for(int i=cnt;i>=;--i){int x=rnk[i];r[fa[x]]+=r[x];}
r[]=;
for(int i=;i<=cnt;++i){int x=rnk[i];sum[x]=sum[fa[x]]+1ll*(l[x]-l[fa[x]])*r[x];}
int now=,le=;
for(int i=;i<=len;++i){
if(ch[now][s[i]-'a'])le++,now=ch[now][s[i]-'a'];
else{
for(;now&&!ch[now][s[i]-'a'];now=fa[now]);
if(now)le=l[now]+,now=ch[now][s[i]-'a'];
else le=,now=;
}
if(now!=)ans+=sum[fa[now]]+1ll*(le-l[fa[now]])*r[now];
}
cout<<ans;
return ;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1600002
#define M 8000002
using namespace std;
typedef long long ll;
char c[],s[M];
int cnt,n,father,pa[N],len,tong[N],rnk[N];
ll sum[N],ans;
int l[N],ch[N][],fa[N],r[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline int ins(int last,int x){
int p=last;
if(ch[p][x]){
int q=ch[p][x];
if(l[p]+==l[q]){r[q]++;return q;}
else{
int nq=++cnt;l[nq]=l[p]+;r[nq]=;//care!!!!!!!!!!!!!!!
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
return nq;
}
}
else{
int np=++cnt;l[np]=l[p]+;r[np]=;
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
if(!p)fa[np]=;
else{
int q=ch[p][x];
if(l[p]+==l[q])fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
return np;
}
}
int main(){
n=rd();cnt=;pa[]=;
for(int i=;i<=n;++i){
father=rd();scanf("%s",c);
pa[i]=ins(pa[father],c[]-'a');
}
scanf("%s",s+);len=strlen(s+);
for(int i=;i<=cnt;++i)tong[l[i]]++;
for(int i=;i<=n;++i)tong[i]+=tong[i-];
for(int i=;i<=cnt;++i)rnk[tong[l[i]]--]=i;
for(int i=cnt;i>=;--i){int x=rnk[i];r[fa[x]]+=r[x];}
r[]=;
for(int i=;i<=cnt;++i){int x=rnk[i];sum[x]=sum[fa[x]]+1ll*(l[x]-l[fa[x]])*r[x];}
int now=,le=;
for(int i=;i<=len;++i){
if(ch[now][s[i]-'a'])le++,now=ch[now][s[i]-'a'];
else{
for(;now&&!ch[now][s[i]-'a'];now=fa[now]);
if(now)le=l[now]+,now=ch[now][s[i]-'a'];
else le=,now=;
}
if(now!=)ans+=sum[fa[now]]+1ll*(le-l[fa[now]])*r[now];
}
cout<<ans;
return ;
}
bzoj3756pty的字符串(后缀自动机+计数)的更多相关文章
- 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)
模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...
- [TJOI2019]甲苯先生和大中锋的字符串——后缀自动机+差分
题目链接: [TJOI2019]甲苯先生和大中锋的字符串 对原串建后缀自动机并维护$parent$树上每个点的子树大小,显然子树大小为$k$的节点所代表的子串出现过$k$次,那么我们需要将$[len[ ...
- Wannafly Camp 2020 Day 2D 卡拉巴什的字符串 - 后缀自动机
动态维护任意两个后缀的lcp集合的mex,支持在串末尾追加字符. Solution 考虑在 SAM 上求两个后缀的 LCP 的过程,无非就是找它们在 fail 树上的 LCA,那么 LCP 长度就是这 ...
- Tjoi2019 甲苯先生和大中锋的字符串 后缀自动机_差分
tjoi胆子好大,直接出了两道送分题...... 都 9102 年了,还有省选出模板题QAQ...... Code: #include <bits/stdc++.h> #define se ...
- 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)
模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...
- HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)
Reincarnation Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- 字符串(后缀自动机):Codeforces Round #129 (Div. 1) E.Little Elephant and Strings
E. Little Elephant and Strings time limit per test 3 seconds memory limit per test 256 megabytes inp ...
- BZOJ 3473: 字符串 [广义后缀自动机]
3473: 字符串 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 354 Solved: 160[Submit][Status][Discuss] ...
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
随机推荐
- Centos 6.x 升级到 7.x
Centos6.5跨越大版本升级到Centos7.4 - Linux学习与应用 - CSDN博客https://blog.csdn.net/whbttst/article/details/805348 ...
- Zabbix appliance One Stop
Download Zabbix appliancehttps://www.zabbix.com/download_appliance
- Json详解以及fastjson使用教程
Json是一种轻量级的数据交换格式,采用一种“键:值”对的文本格式来存储和表示数据,在系统交换数据过程中常常被使用,是一种理想的数据交换语言.在使用Java做Web开发时,不可避免的会遇到Json的使 ...
- 运行Spark-shell,解决Unable to load native-hadoop library for your platform
启动spark后,运行bin/spark-shell会出现一个警告 提君博客原创 WARN util.NativeCodeLoader: Unable to load native-hadoop li ...
- .Net在操作mysql查询的时候出现“: Unknown column 'UserName' in 'where clause'”错误
今天使用.Net操作mysql查询的时候,如果加上条件查询的时候就会出现 Unknown column 'UserName' in 'where clause'这个错,不加条件直接select * f ...
- linux通过命令行查看MySQL编码并修改-简洁版方法
云服务器环境:CentOS 7.4 因为服务器配置较低,故使用MySQL5.5 未进行设置前 1.查看字符编码: mysql> show variables like '%character%' ...
- MyBatis的XML中使用内部类的方式
内部类需要使用$符号连接,而不是点.,如 com.pingan.job.openapi.model.SMSESBResult$ReceiveResult$ResultInfo 从CSDN论坛查到的. ...
- Java使用RabbitMQ之订阅分发(Topic)
使用RabbitMQ进行消息发布和订阅,生产者将消息发送给转发器(exchange),转发器根据路由键匹配已绑定的消息队列并转发消息,主题模式支持路由键的通配. 生产者代码: package org. ...
- 转载 -- CSS3 中关于 select 下拉列表的样式
截图效果:
- vue axios 封装(三)
封装三: import axios from 'axios' import { Message, MessageBox } from 'element-ui' import store from '. ...