题目大意:给定一个初始字符串,提供两种操作:
1.在这个字符串的后面连接一个字符串
2.询问某个字符串在当前串中出现了多少次
SAM大叔的自动机~~
对于每个询问就是在后缀自动机上找到该子串所对应的节点 找不到返回0
然后这个节点的Right集合的大小就是这个子串的出现次数
每次Extend的时候将新建节点沿着parent指针到根的路径上所有点的Right集合大小+1即可
分裂节点的时候要将Right集合一并复制
这方法虽然暴力但是非常有效
由于parent是一棵树,所以可以用LCT来维护这棵树 Extend的时候直接路径修改 O(logn)
结果尼玛反倒变慢了。。。
此外就是解密过程是不改变mask的值的 mask的值只在Query的时候改变 小心被坑
暴力:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int q,mask;
char s[3003003];
namespace Suffix_Automaton{
struct SAM{
SAM *son[26],*parent;
int dpt,size;
SAM(int _=0):parent(0x0),dpt(_),size(0)
{
memset(son,0,sizeof son);
}
}*root=new SAM,*last=root;
void Extend(int x)
{
SAM *p=last;
SAM *np=new SAM(p->dpt+1);
while(p&&!p->son[x])
p->son[x]=np,p=p->parent;
if(!p) np->parent=root;
else
{
SAM *q=p->son[x];
if(q->dpt==p->dpt+1)
np->parent=q;
else
{
SAM *nq=new SAM(p->dpt+1);
memcpy(nq->son,q->son,sizeof nq->son);
nq->parent=q->parent;
q->parent=nq;np->parent=nq;
nq->size=q->size;
for(;p&&a