【BZOJ2555】SubString(后缀自动机,LCT)
题意:给你一个字符串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)的更多相关文章
- luogu5212/bzoj2555 substring(后缀自动机+动态树)
对字符串构建一个后缀自动机. 每次查询的就是在转移边上得到节点的parent树中后缀节点数量. 由于强制在线,可以用动态树维护后缀自动机parent树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...
- bzoj 2555 SubString —— 后缀自动机+LCT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2555 建立后缀自动机,就可以直接加入新串了: 出现次数就是 Right 集合的大小,需要查询 ...
- 【BZOJ2555】SubString 后缀自动机+LCT
[BZOJ2555]SubString Description 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2 ...
- bzoj 2555: SubString 后缀自动机+LCT
2555: SubString Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 688 Solved: 235[Submit][Status][Dis ...
- bzoj 2555 SubString——后缀自动机+LCT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2555 要维护 right 集合的大小.因为 fa 会变,且 fa 构成一棵树,所以考虑用 L ...
- BZOJ2555 SubString 【后缀自动机 + LCT】
题目 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 输入 ...
- bzoj2555(后缀自动机+LCT)
题目描述 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 题解 做法很自然,建出后缀自动机,维护每个节点的right ...
- bzoj 2555: SubString【后缀自动机+LCT】
一直WA--找了半天错的发现居然是解密那里的mask其实是不能动的--传进去的会变,但是真实的那个不会变-- 然后就是后缀自动机,用LCT维护parent树了--注意不能makeroot,因为自动机的 ...
- SPOJ1811 LCS - Longest Common Substring(后缀自动机)
A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the s ...
- 51nod 1600 Simple KMP【后缀自动机+LCT】【思维好题】*
Description 对于一个字符串|S|,我们定义fail[i],表示最大的x使得S[1..x]=S[i-x+1..i],满足(x<i) 显然对于一个字符串,如果我们将每个0<=i&l ...
随机推荐
- day37—javascript对表格table的操作应用(二)
转行学开发,代码100天——2018-04-22 昨天学习了JavaScript对table的基本操作,包括表格的创建,表格元素的获取,隔行换色及鼠标动作等.今天主要学习table的搜索查询及排序操作 ...
- delphi 手势 识别 哈哈
本例尝试在 OnGesture 事件中响应 sgLeft.sgRight 手势; 操作步骤: 1.加 TGestureManager 控件如窗体: GestureManager1; 2.设置窗体属性 ...
- 深入浅出WPF(Binding篇1)
Binding在业界的使用一直是音译而来的,称为"Binding".Binding的源是逻辑数据对象,目标则是UI层上面的控件对象.数据通过Binding送达UI层,被UI层展示出 ...
- vue的概述
一.Vue的概述 Vue的开发模式 和 之前接触的jQuery.原生JSDOM操作是不同的,之前要想修改试图,首先找元素:在使用Vue时,专心把精力放在修改数据.DOM驱动 ---> 数据驱动. ...
- Mac009--Axure RP安装
Mac--Axure RP安装 一.下载Axure RP8.0 下载网址:https://www.axure.com/download (下载mac版本) Axure RP说明: Axure RP是 ...
- < python PIL - 批量图像处理 - 生成自定义大小图像 >
< python PIL - 批量图像处理 - 生成自定义大小图像 > 直接用python自带的PIL图像库,对一个文件夹下所有jpg/png的图像进行自定义像素变换 from PIL i ...
- SAP选择屏幕开发(一)(转)
原文链接:https://blog.csdn.net/wtxhai/article/details/90632686 用户通过屏幕操作来实现与SAP的数据交互,而SAP的屏幕开发一般分为两种,一种是通 ...
- 耗时近一个月,终于录完了VUE.JS2.0前端视频教程!
这次课录制的比较辛苦,圣诞节时原本已经快录制完成了,偶然的一次,播放了一下,感觉不满意,好几篇推倒重来,所以今天才结束. vue.js2.0是Vue.JS的最新版本,视频教程还不多,如果你看到了,学到 ...
- ubuntu离线安装mysql
一:ubuntu离线安装mysql 转载来源:https://blog.csdn.net/liuhuoxingkong/article/details/80696574 参考文章:https://ww ...
- 1、引言(Introduction)
1.1 欢迎 在生活中用到的机器学习算法: (1)打开谷歌.必应搜索到你需要的内容,正是因为他们有良好的学习算法 (2)每次您阅读您的电子邮件垃圾邮件筛选器,可以帮你过滤大量的垃圾邮件 机器学习为什么 ...