先考虑没有动态加字符怎么做。计算每个节点的贡献,当|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. 使用Qt Creator作为Linux IDE,代替Vim:实现两台Linux电脑远程部署和gdb调试(一台电脑有桌面系统,一台电脑无桌面系统)

      版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/libaineu2004/article/details/62423830 尊重作者,支持原创,如 ...

  2. Linux | Vim使用

    Linux vi/vim 所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在. 但是目前我们使用比较多的是 vim 编辑器. vim 具有程序编辑的能力,可以主 ...

  3. java写文件实现换行

    Java 写文件实现换行   第一种: 写入的内容中利用\r\n进行换行 File file = new File("D:/text"); try { if(!file.exist ...

  4. PAT 甲级 1034 Head of a Gang (30 分)(bfs,map,强连通)

    1034 Head of a Gang (30 分)   One way that the police finds the head of a gang is to check people's p ...

  5. VCL组件之TPanel

    TPanel位于Standard组件面板上,也是常用的一种容器控件.面板的一个优点就是放在面板上的组件称为面板的一部分,因此它们与面板一起移动.这在设计阶段很有用. Panel组件的大部分功能在于其A ...

  6. laravel服务提供者类说明

    IoC 是将内部设计的类交给系统去控制,但是有些类在初始化的时候,需要制定特定的参数,或者当你需要将实现类绑定到某个接口,这时候就必须对这些依赖进行配置,系统才能正确解析并引用. register 而 ...

  7. 异地协作,A地上传jar包到B地服务器上传速率慢

    在A地使用ftp服务器,再登录B地的目标服务器,使用ftp命令从ftp服务器下载文件,速度快点,下载带宽比上传带宽要大一点 https://blog.csdn.net/df0128/article/d ...

  8. Springboot 参数中传List

    使用REST API时,经常会有get/delete方法需要传一个list的情况,如果使用post难免有点破坏规则,实际上参数传list是可以做到的 方法一: 后端代码如下: @DeleteMappi ...

  9. ASP.NET MVC4中的异步控制器

    在抛弃了对.NET 3的支持之后, ASP.NET MVC 4 彻底拥抱了Task类库, 你不需要再蛋疼的给每个Action写两个方法, 也无需傻傻的手动对异步Action计数器增减了(AsyncMa ...

  10. Shiro认证、角色、权限

    Apache Shiro 是 Java 的一个安全框架.Shiro 可以帮助我们完成:认证.授权.加密.会话管理.与 Web 集成.缓存等. Shiro的内置Realm:IniRealm和JdbcRe ...