先考虑没有动态加字符怎么做。计算每个节点的贡献,当|right|>=k时将len-lenfa计入即可。

  动态加字符后,这个东西难以用LCT维护。于是考虑离线。建完SAM后,容易发现每个节点在时间上的一段后缀提供贡献,且具体时间就是其right集合中的第k小。主席树或线段树合并求出即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define N 500010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,k,fail[N],len[N],id[N],q[N],p[N],tmp[N],f[N],root[N],cnt,last,tot;
ll ans[N];
char s[N];
map<int,int> son[N];
struct data{int l,r,x;
}tree[N<<4];
int newnode(){cnt++;son[cnt].clear();fail[cnt]=len[cnt]=0;return cnt;}
void extend(int c)
{
int x=newnode(),p=last;last=x;len[x]=len[p]+1;id[len[x]]=x;
while (!son[p][c]&&p) son[p][c]=x,p=fail[p];
if (!p) fail[x]=1;
else
{
int q=son[p][c];
if (len[p]+1==len[q]) fail[x]=q;
else
{
int y=newnode();
len[y]=len[p]+1;
son[y]=son[q];
fail[y]=fail[q],fail[q]=fail[x]=y;
while (son[p][c]==q) son[p][c]=y,p=fail[p];
}
}
}
void ins(int &k,int l,int r,int x)
{
tree[++tot]=tree[k],k=tot;tree[k].x++;
if (l==r) return;
int mid=l+r>>1;
if (x<=mid) ins(tree[k].l,l,mid,x);
else ins(tree[k].r,mid+1,r,x);
}
int merge(int x,int y,int l,int r)
{
if (!x||!y) return x|y;
int k=++tot;tree[k].x=tree[x].x+tree[y].x;
if (l<r)
{
int mid=l+r>>1;
tree[k].l=merge(tree[x].l,tree[y].l,l,mid);
tree[k].r=merge(tree[x].r,tree[y].r,mid+1,r);
}
else tree[k].l=tree[k].r=0;
return k;
}
int query(int k,int l,int r,int x)
{
if (l==r) return l;
int mid=l+r>>1;
if (tree[tree[k].l].x>=x) return query(tree[k].l,l,mid,x);
else return query(tree[k].r,mid+1,r,x-tree[tree[k].l].x);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
while (scanf("%d%d%d",&n,&m,&k)!=EOF)
{
scanf("%s",s+1);cnt=0,last=1;newnode();
for (int i=1;i<=n;i++) extend(s[i]-'a');int t=0;
for (int i=1;i<=m;i++)
{
int op=read();
if (op==1) n++,extend(getc()-'a');
else q[++t]=n;
}
for (int i=1;i<=n;i++) tmp[i]=0;
for (int i=1;i<=cnt;i++) tmp[len[i]]++;
for (int i=1;i<=n;i++) tmp[i]+=tmp[i-1];
for (int i=1;i<=cnt;i++) p[tmp[len[i]]--]=i;
for (int i=1;i<=n;i++) ans[i]=0;tot=0;
for (int i=0;i<=cnt;i++) root[i]=0;
for (int i=1;i<=n;i++) ins(root[id[i]],1,n,i);
for (int i=cnt;i>=1;i--)
{
int x=p[i];
if (tree[root[x]].x>=k) ans[query(root[x],1,n,k)]+=len[x]-len[fail[x]];
root[fail[x]]=merge(root[fail[x]],root[x],1,n);
}
for (int i=1;i<=n;i++) ans[i]+=ans[i-1];
for (int i=1;i<=t;i++) printf("%I64d\n",ans[q[i]]);
}
return 0;
}

  

HDU4641 K-string(后缀自动机+线段树合并)的更多相关文章

  1. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  2. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

  3. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  4. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  5. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  6. bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并)

    bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并) bzoj Luogu 给出一个字符串 $ S $ 及 $ q $ 次询问,每次询问一个字符串 $ T $ ...

  7. BZOJ5417[Noi2018]你的名字——后缀自动机+线段树合并

    题目链接: [Noi2018]你的名字 题目大意:给出一个字符串$S$及$q$次询问,每次询问一个字符串$T$有多少本质不同的子串不是$S[l,r]$的子串($S[l,r]$表示$S$串的第$l$个字 ...

  8. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

  9. 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 657  Solved: 274[Su ...

随机推荐

  1. 【spring源码分析】IOC容器初始化——查漏补缺(五)

    前言:我们知道在Spring中经常使用配置文件的形式对进行属性的赋值,那配置文件的值是怎么赋值到属性上的呢,本文将对其进行分析. 首先了解一个类:PropertySourcesPlaceholderC ...

  2. C# - ZIP 压缩流

    C# - ZIP 压缩流 参考资料 https://docs.microsoft.com/en-us/dotnet/api/system.io.compression.ziparchive?view= ...

  3. Win+数字快速启动/切换指定程序

    Windows键+数字,可以快速启动任务栏上的程序 按下按下Win+4桌面将切换到排序第4的程序:页也就是谷歌浏览器. 今天刚发现这个小功能.   文章来源:外星人来地球 欢迎关注,有问题一起学习欢迎 ...

  4. 关于Mysql-unknow-column-in-where-clause

    写在前边: 已经很久不更新了啊,整个2月份几乎没有遇到什么新鲜事.直到昨天我又犯了一次傻,貌似只有我犯傻的时候才有材料可以跟大家分享- 问题表现: mysql 报错: unknow column 's ...

  5. supervisor :a running process with pid = 0,程序PID为0

    Neo君作为一只小白,今天踩到了一个supervisor的坑. 如上图所示,出现这种情况后,想把这个进程停止.或者重启,甚至stop all它还是这个样子,如下图(马赛克部分为进程名称): 一:背景 ...

  6. Ubunut16.04 安装 g++ gcc 降级

    1. 查看gcc版本和g++版本 cd /usr/bin ls -l gcc* ls -l g++* 2. 安装gcc和g++ 4.4版本 sudo apt-get install gcc-4.4 g ...

  7. djando模板----第一django模板应用

    Django模板 我们已经知道,模板函数的函数的返回值就是返回给客户端的数据,但如果返回数据很复杂,如果一个非常大的html页面,直接将页面代码固化在python脚本文件中是不合适的,当然 也可以将h ...

  8. EOF使用

    1.cat向文件覆盖内容 cat > local.repo << EOF [local]name=localbaseurl=file:///mnt/cdromgpgcheck=0en ...

  9. droid AVD创建及设置中各参数详解

    设置AVD时有些参数比较模糊,特地找了篇文章,大家参考下! 本文根据如下的模拟器安装做一些解释: Name: 自定义虚拟的名称,不能有空格或者其他非法字符,否则不能创建,即Creat AVD不能高亮点 ...

  10. HTML滚动时位置固定

    现在显示器一般都是宽屏,网页两端常常会留白. 两边可能会放一些推荐.标签或是导航什么的辅助模块. 现在有的网站页面内容过长时,用户将滚动条向下拉时,拉到一定程度,左右两侧的辅助模块就会固定在指定位置, ...