BZOJ2555 SubString 【后缀自动机 + LCT】
题目
懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
输入格式
第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0

读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
输出格式
输入样例
2
A
QUERY B
ADD BBABBBBAAB
输出样例
0
提示
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20
题解
大码题。。我就知道我会WA【到头来是解压错了= =,注意解压时的mask不是你维护的mask,你维护的mask值在解压前后不应改变】
由后缀自动机的性质,我们给SAM上的点赋值,在主链上的点权为1【即插入的不包括拓展的点】,其它点为0
权值为1的点在parent树上都是叶子节点,而一个节点所形成相同的串的数量就是该节点在parent树中的子树的叶子节点数
那这就好办了,我们用LCT维护parent树,每次加点就将ta到根节点加上ta的权值
由于树根始终不变而且树边有向,我们可以把LCT写得简单一点
【orz hzwer】
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define isr(u) (ch[fa[u]][1] == u)
#define isrt(u) (!fa[u] || (ch[fa[u]][0] != u && ch[fa[u]][1] != u))
#define ls ch[u][0]
#define rs ch[u][1]
using namespace std;
const int maxn = 1200005,maxm = 3000005,INF = 1000000000;
int fa[maxn],tag[maxn],val[maxn],ch[maxn][2];
int pre[maxn],son[maxn][26],step[maxn],cnt,last,n;
char s[maxm];
void add(int u,int v){if (u) val[u] += v,tag[u] += v;}
void pd(int u){
if (tag[u]) add(ls,tag[u]),add(rs,tag[u]),tag[u] = 0;
}
void push_down(int u){
if (!isrt(u)) push_down(fa[u]); pd(u);
}
void spin(int u){
int s = isr(u),f = fa[u];
fa[u] = fa[f]; if (!isrt(f)) ch[fa[f]][isr(f)] = u;
ch[f][s] = ch[u][s ^ 1]; if (ch[u][s ^ 1]) fa[ch[u][s ^ 1]] = f;
fa[f] = u; ch[u][s ^ 1] = f;
}
void splay(int u){
for (push_down(u); !isrt(u); spin(u))
if (!isrt(fa[u])) spin((isr(u) ^ isr(fa[u])) ? u : fa[u]);
}
void Access(int u){
for (int v = 0; u; u = fa[v = u]) splay(u),rs = v;
}
void Cut(int u){
Access(u); splay(u); add(ls,-val[u]);
fa[ls] = 0; ls = 0;
}
void Link(int u,int f){
fa[u] = f; Access(f); splay(f); add(f,val[u]);
}
void ins(int x){
int p = last,np = ++cnt;
last = np; val[np] = 1; step[np] = step[p] + 1;
while (p && !son[p][x]) son[p][x] = np,p = pre[p];
if (!p) pre[np] = 1,Link(np,1);
else {
int q = son[p][x];
if (step[q] == step[p] + 1) pre[np] = q,Link(np,q);
else {
int nq = ++cnt; step[nq] = step[p] + 1;
memcpy(son[nq],son[q],sizeof(son[q]));
pre[nq] = pre[q]; Link(nq,pre[q]);
pre[np] = nq; Link(np,nq);
Cut(q); pre[q] = nq; Link(q,nq);
while (son[p][x] == q) son[p][x] = nq,p = pre[p];
}
}
}
int MASK;
void Mask(int mask){
n = strlen(s);
for (int j = 0; j < n; j++){
mask = (mask * 131 + j) % n;
swap(s[j],s[mask]);
}
}
int solve(){
int u = 1; scanf("%s",s); Mask(MASK);
for (int i = 0; i < n; i++)
if (!(u = son[u][s[i] - 'A'])) return 0;
splay(u);
return val[u];
}
int main(){
int Q,ans; scanf("%d",&Q);
scanf("%s",s);
n = strlen(s); cnt = last = 1;
for (int i = 0; i < n; i++) ins(s[i] - 'A');
while (Q--){
scanf("%s",s);
if (s[0] == 'A'){
scanf("%s",s); Mask(MASK);
for (int i = 0; i < n; i++) ins(s[i] - 'A');
}
else printf("%d\n",ans = solve()),MASK ^= ans;
}
return 0;
}
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(后缀自动机+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 ...
随机推荐
- python 多进程简单调用
python 多进程简 #!/usr/bin/env python #-*- coding:utf-8 -*- # author:leo # datetime:2019/5/28 10:03 # so ...
- PageHelper 记录总条数不正确问题处理
//PageHelper.startPage会返回一个page对象,这个对象在查询结果出来后会把页数,记录总数给page对象,用page.getPages()和getTotal()获取页数和记录总数. ...
- CSVDE
csvde -f C:\export_OrganizationalUnit.csv -r '(objectClass=organizationalUnit)' -l 'displayName,prox ...
- 用gulp把less文件编译成css文件
第一次使用gulp构建工具,使用gulp将.less文件编译成.css文件并输出.根据视频做了笔记.提供新手和自己以后做参考. HTML文件 <!DOCTYPE html> <htm ...
- Ubuntu解决winscp连接不上虚拟机问题
前几天在配置虚拟机的时候,尝试用winscp连接Ubuntu,结果连接被拒绝.原因:Ubuntu的ssh服务需要自己安装和启动,在没启动之前,是无法连接上去的 解决方案: 我们可以输入:ssh loc ...
- 03_15_interface
03_15_interface 1. 接口 接口是抽象方法和常量值的定义的集合. 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现. 2. 接口特性 接口 ...
- vue框架初学习的基本指令
学习地址:<ahref="https: cn.vuejs.="" org="" "="" targe ...
- bootstrap validation submit
表单提交校验功能 前端样式用bootstrap,依赖jquery,应用jquery自带的validation插件. 其实校验是一个小功能,做了还几天主要是因为碰到了两个问题,一个是对于提示信息样式添加 ...
- 认识mysql(4)
今日是MySQL的第四篇,难度会稍微加大,加油! 开始吧! 1.外键(foreign key) 1.定义:让当前表字段的值在另一个表的范围内选择 2.语法: foreign key(参考字段名) r ...
- HDU 5971 二分图判定
Wrestling Match Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)T ...