题意:给你一个字符串init,要求你支持两个操作

(1):在当前字符串的后面插入一个字符串

(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)

你必须在线支持这些操作。

长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000

思路:因为有加边,删边,加点操作,需要动态维护SAM中每个right集合的大小,所以使用LCT维护

需要维护根节点=1号点到每个结点路径上的和,因为固定了1号点为根节点所以不需要makeroot和rev标记

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> Pll;
typedef vector<int> VI;
typedef vector<PII> VII;
typedef pair<ll,int>P;
#define N 1200010
#define M 210000
#define fi first
#define se second
#define MP make_pair
#define pi acos(-1)
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
#define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
#define lowbit(x) x&(-x)
#define Rand (rand()*(1<<16)+rand())
#define id(x) ((x)<=B?(x):m-n/(x)+1)
#define ls p<<1
#define rs p<<1|1 const int MOD=1e9+,inv2=(MOD+)/;
double eps=1e-;
int INF=<<;
ll inf=5e13;
int dx[]={-,,,};
int dy[]={,,-,}; int mask;
char s[];
string chars; int read()
{
int v=,f=;
char c=getchar();
while(c<||<c) {if(c=='-') f=-; c=getchar();}
while(<=c&&c<=) v=(v<<)+v+v+c-,c=getchar();
return v*f;
} void gets(int mask)
{
scanf("%s",s);
chars=s;
for(int j=;j<chars.length();j++)
{
mask=(mask*+j)%chars.length();
char t=chars[j];
chars[j]=chars[mask];
chars[mask]=t;
}
} struct lct
{
int t[N][],w[N],fa[N],q[N],rev[N],tag[N],top; void add(int x,int y)
{
if(x)
{
w[x]+=y;
tag[x]+=y;
}
} int isroot(int x)
{
return ((t[fa[x]][]!=x)&&(t[fa[x]][]!=x));
} void pushdown(int x)
{
int l=t[x][],r=t[x][];
if(tag[x])
{
add(l,tag[x]);
add(r,tag[x]);
tag[x]=;
}
} void rotate(int x)
{
int y=fa[x],z=fa[y];
int l=(t[y][]==x),r=l^;
if(!isroot(y)) t[z][t[z][]==y]=x;
fa[t[x][r]]=y,fa[y]=x,fa[x]=z;
t[y][l]=t[x][r],t[x][r]=y;
} void splay(int x)
{
top=;
q[++top]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
while(top) pushdown(q[top--]);
while(!isroot(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if((t[y][]==x)^(t[z][]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
} void access(int x)
{
for(int k=;x;k=x,x=fa[x])
{
splay(x);
t[x][]=k;
}
} void link(int x,int y)
{
fa[x]=y;
access(y);
splay(y);
add(y,w[x]);
} void cut(int x)
{
access(x);
splay(x);
add(t[x][],-w[x]);
fa[t[x][]]=;
t[x][]=;
} }lct; struct sam
{
int cnt;
int F[N],ch[N][];
int st[N],b[N],bl[N],c[N];
int p,np,q,nq; sam()
{
cnt=np=;
} void extend(int x)
{
p=np; st[np=++cnt]=st[p]+;
while(p&&!ch[p][x])
{
ch[p][x]=np;
p=F[p];
}
lct.w[np]=;
if(!p) F[np]=,lct.link(np,);
else if(st[p]+==st[q=ch[p][x]]) F[np]=q,lct.link(np,q);
else
{
st[nq=++cnt]=st[p]+;
memcpy(ch[nq],ch[q],sizeof ch[q]);
F[nq]=F[q];
lct.link(nq,F[q]);
F[np]=F[q]=nq;
lct.cut(q);
lct.link(q,nq);
lct.link(np,nq);
while(ch[p][x]==q)
{
ch[p][x]=nq;
p=F[p];
}
}
} void build()
{
scanf("%s",s);
int n=strlen(s);
rep(i,,n-) extend(s[i]-'A');
} void add()
{
gets(mask);
int n=chars.length();
rep(i,,n-) extend(chars[i]-'A');
} int query()
{
gets(mask);
int p=,n=chars.length();
rep(i,,n-)
{
p=ch[p][chars[i]-'A'];
if(!p) return ;
}
lct.splay(p);
return lct.w[p];
} }sam; int main()
{
int Q;
scanf("%d",&Q);
sam.build();
while(Q--)
{
scanf("%s",s);
if(s[]=='A') sam.add();
else
{
int ans=sam.query();
printf("%d\n",ans);
mask^=ans;
}
}
return ;
}

【BZOJ2555】SubString(后缀自动机,LCT)的更多相关文章

  1. luogu5212/bzoj2555 substring(后缀自动机+动态树)

    对字符串构建一个后缀自动机. 每次查询的就是在转移边上得到节点的parent树中后缀节点数量. 由于强制在线,可以用动态树维护后缀自动机parent树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...

  2. bzoj 2555 SubString —— 后缀自动机+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2555 建立后缀自动机,就可以直接加入新串了: 出现次数就是 Right 集合的大小,需要查询 ...

  3. 【BZOJ2555】SubString 后缀自动机+LCT

    [BZOJ2555]SubString Description 懒得写背景了,给你一个字符串init,要求你支持两个操作         (1):在当前字符串的后面插入一个字符串         (2 ...

  4. bzoj 2555: SubString 后缀自动机+LCT

    2555: SubString Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 688  Solved: 235[Submit][Status][Dis ...

  5. bzoj 2555 SubString——后缀自动机+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2555 要维护 right 集合的大小.因为 fa 会变,且 fa 构成一棵树,所以考虑用 L ...

  6. BZOJ2555 SubString 【后缀自动机 + LCT】

    题目 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 输入 ...

  7. bzoj2555(后缀自动机+LCT)

    题目描述 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 题解 做法很自然,建出后缀自动机,维护每个节点的right ...

  8. bzoj 2555: SubString【后缀自动机+LCT】

    一直WA--找了半天错的发现居然是解密那里的mask其实是不能动的--传进去的会变,但是真实的那个不会变-- 然后就是后缀自动机,用LCT维护parent树了--注意不能makeroot,因为自动机的 ...

  9. SPOJ1811 LCS - Longest Common Substring(后缀自动机)

    A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the s ...

  10. 51nod 1600 Simple KMP【后缀自动机+LCT】【思维好题】*

    Description 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i&l ...

随机推荐

  1. .net 学习官网

    https://docs.microsoft.com

  2. python:while循环语句及练习题

    while循环语句及练习题 Python 编程中 while 语句用于循环执行程序,即在某条件下,循环执行某段程序,以处理需要重复处理的相同任务.其基本形式为: while 判断条件: 执行语句... ...

  3. 问题 1436: 地宫取宝 (dp)

    题目传送门 时间限制: 1Sec 内存限制: 128MB 提交: 423 解决: 94 题目描述 X  国王有一个地宫宝库.是  n  x  m  个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标 ...

  4. C# Winform 窗体界面”假死”后台线程阻塞 解决办法–BeginInvoke

    原文:C# Winform 窗体界面"假死"后台线程阻塞 解决办法–BeginInvoke 这个方法可以用在任何后台任务耗时较长,造成界面“假死”界面控件不更新的情况. 比如要要执 ...

  5. nginx的4层负载均衡配置

    前言:所谓四层就是基于IP+端口的负载均衡:七层就是基于URL等应用层信息的负载均衡:同理,还有基于MAC地址的二层负载均衡和基于IP地址的三层负载均衡. 换句换说,二层负载均衡会通过一个虚拟MAC地 ...

  6. Python之反向迭代

    需求:得到反方向迭代一个序列解决:使用内置的 reversed() 函数 a = [1, 2, 3, 4] for x in reversed(a): print(x) # 4 3 2 1 反向迭代仅 ...

  7. CSS中quotes属性以及content的open(close)-quotes属性

    定义和用法 quotes 属性设置嵌套引用(embedded quotation)的引号类型. 可能的值 值 描述 none 规定 "content" 属性的 "open ...

  8. C#使用Process启动exe程序,不弹出控制台窗口的方法

    背景:使用wkhtmltopdf工具将html转换成pdf时,这个工具在进行转换时会弹出命令行窗口显示转换过程,但是在项目运行时弹出服务器突然弹出控制台窗口会很奇怪,尤其是当转换多个时.解决这个问题 ...

  9. go语言学习之从例子开始

    [目录] go语言从例子开始之Example1.helloworld go语言从例子开始之Example2.类型 go语言从例子开始之Example3.变量 go语言从例子开始之Example4.常量 ...

  10. Java并发(具体实例)—— 构建高效且可伸缩的结果缓存

    这个例子来自<Java并发编程实战>第五章.本文将开发一个高效且可伸缩的缓存,文章首先从最简单的HashMap开始构建,然后分析它的并发缺陷,并一步一步修复. hashMap版本     ...