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即可. 但即使忽略判断前缀的时间,光是连边的 ...
随机推荐
- Eclipse lombok java
Stablehttps://projectlombok.org/features/all Lombok介绍及使用方法 - holten - 博客园http://www.cnblogs.com/holt ...
- input type=date时,时间数据回填,报错The specified value "2019-0404-18" does not conform to the required format, "yyyy-MM-dd".
<input autocomplete id="start-time" name="start_time" type="date" c ...
- hive之size函数和cast转换函数
size返回map集合中元素的个数: cast函数将一种类型的数据转换成其他格式的数据
- linux audit (9)--生成audit报表
aureport这个命令可以生成一个总结性的柱状图报表,默认情况下,在/var/log/audit目录下的所有日志文件都会生成一个报表,也可以使用如下命令来指定一个不同的文件,aureport opt ...
- windows 10 multi virtual desktop keyboard shortcut
windows 10 multi virtual desktop keyboard shortcut windows 10 multi desktop keyboard shortcut https: ...
- Vue之变量、数据绑定、事件绑定使用举例
vue1.html <!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/19 ...
- Python——列表操作
一.列表中所有元素出现的次数,并输出为字典模式 def count_list(list): b_list = {} for i in set(list): b_list[i] = list.count ...
- replace只能输入小数
case "checkPrice": tr.find(".layui-table-edit").keyup(function () { var $input = ...
- C-Lodop提示“网页还没下载完毕,请稍等一下再操作.”
该提示在Lodop旧版本中是: 提示"WebSocket没准备好,点确定继续",提示“C-Lodop没准备好”,新版本修改了该提示的描述“网页还没下载完毕,请稍等一下再操作.”,让 ...
- A Simple Problem with Integers(线段树区间更新模板)
最基本的线段树的区间更新及查询和 用tag(lazy)数组来“延缓”更新,查询或添加操作必须进行pushdown操作,即把tag从p传到lp和rp并清楚tag[p],既然得往lp和rp递归,那么就可以 ...