BZOJ2555——SubString
0、题目很短,就不概括了
给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
1、分析:
a)首先我们来看40%的数据,我们可以建立后缀自动机,对于插入串,我们直接暴力的insert,不要怂。。。询问的话我们就在后缀自动机上的tranc上面跑。。然后暴力的统计right集合的数量,遍历这个子树,因为每一次都会更新,所以不能预处理,然后40pts get,时间复杂度O(n2)
b)也就是正解,我们发现a)做法的主要复杂度在于询问,询问就是求right集合,那么我们怎么快速的维护right集合呢?我们发现这个东西是个树,然后动态加点,然后维护子树和,是不是想到了lct呢?然而lct并不能维护子树的信息,是不是想到了toptree….然而toptree我都不会,怎么能写呢?所以吴大爷说这个是简单版的toptree,其实是lct…..然后我们在lct中多维护一个信息。这个信息表示他的所有虚儿子的子树的和。。那么access的时候我们要更新一下这个信息,还有link操作,为什么link操作也要维护呢?因为link操作连的虚边QAQ….然后每次询问我们可以直接依旧在后缀自动机里面一点一点的向下走,然后我们再查询这个子树,查询之前我们要Access一下,这样答案就是这个点的虚儿子+这个点是不是后缀咯。。。有个问题就是在getans的函数中我把return的p -> vs + p -> w改成p -> s就wa了QAQ,跪求神犇帮我看看
时间复杂度O(nlogn+n)
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
inline int read(){
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9'){
if(ch == '-') f = -1;
ch = getchar();
}
while('0' <= ch && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
namespace LCT{
struct Node{
Node *ch[2], *fa;
int s, vs, w;
bool rev;
Node();
inline int which();
inline void reverse(){
if(this){
rev ^= 1;
swap(ch[0], ch[1]);
}
}
inline void pd(){
if(rev){
ch[0] -> reverse();
ch[1] -> reverse();
rev = false;
}
}
inline void maintain(){
s = vs + w + ch[0] -> s + ch[1] -> s;
}
} *null = new Node, tree[1500010], *pos[1500010];
int tot;
Node::Node(){
rev = false;
s = vs = w = 0;
ch[0] = ch[1] = fa = null;
}
inline int Node::which(){
if(fa == null || (this != fa -> ch[0] && this != fa -> ch[1])) return -1;
return this == fa -> ch[1];
}
inline void rotate(Node *o){
Node *p = o -> fa;
int l = o -> which(), r = l ^ 1;
o -> fa = p -> fa;
if(p -> which() != -1) p -> fa -> ch[p -> which()] = o;
p -> ch[l] = o -> ch[r];
if(o -> ch[r]) o -> ch[r] -> fa = p;
o -> ch[r] = p; p -> fa = o;
o -> ch[r] -> maintain();
o -> maintain();
}
inline void splay(Node *o){
static stack<Node*> st;
if(!o) return;
Node *p = o;
while(1){
st.push(p);
if(p -> which() == -1) break;
p = p -> fa;
}
while(!st.empty()){
st.top() -> pd(); st.pop();
}
while(o -> which() != -1){
p = o -> fa;
if(p -> which() != -1){
if(p -> which() ^ o -> which()) rotate(o);
else rotate(p);
}
rotate(o);
}
}
inline void Access(Node *o){
Node *y = null;
while(o != null){
// if(o == NULL) printf("fuck\n");
splay(o);
// printf("%d\n", o -> vs);
o -> vs += o -> ch[1] -> s;
o -> ch[1] = y;
o -> vs -= y -> s;
o -> maintain();
y = o; o = o -> fa;
}
}
inline void MovetoRoot(Node *o){
Access(o);
splay(o);
o -> reverse();
}
inline Node* FindRoot(Node *o){
Access(o);
splay(o);
while(o -> ch[0] != null) o = o -> ch[0];
return o;
}
inline void Link(Node *x, Node *y){
MovetoRoot(x);
x -> fa = y;
y -> vs += x -> s;
y -> maintain();
}
inline void Cut(Node *x, Node *y){
MovetoRoot(x);
Access(y);
splay(y);
y -> ch[0] = x -> fa = null;
y -> maintain();
}
}
using namespace LCT;
struct node{
int tranc[27], len, fa;
} a[1500010];
int p, q, np, nq;
int tail, cnt;
inline void insert(int k){
p = tail;
pos[cnt + 1] = &tree[cnt + 1];
np = ++ cnt;
a[np].len = a[tail].len + 1;
for(p = tail; p && !a[p].tranc[k]; p = a[p].fa) a[p].tranc[k] = np;
if(!p) a[np].fa = 1;
else{
q = a[p].tranc[k];
if(a[q].len == a[p].len + 1) a[np].fa = q;
else{
pos[cnt + 1] = &tree[cnt + 1];
a[nq = ++ cnt] = a[q];
a[q].fa = a[np].fa = nq;
a[nq].len = a[p].len + 1;
for(; a[p].tranc[k] == q; p = a[p].fa) a[p].tranc[k] = nq;
Cut(pos[q], pos[a[nq].fa]);
Link(pos[nq], pos[a[nq].fa]);
Link(pos[nq], pos[q]);
}
}
tail = np;
pos[np] -> fa = pos[a[np].fa];
MovetoRoot(pos[np]);
// printf("%d\n", k);
pos[np] -> w = 1;
pos[np] -> maintain();
}
inline int getans(Node *p){
MovetoRoot(pos[1]);
Access(p);
return p -> w + p -> vs;
}
char s[1000010];
int main(){
null -> ch[0] = null -> ch[1] = null -> fa = NULL;
null -> vs = null -> s = null -> w = 0;
null -> rev = false;
int n = read();
scanf("%s", s + 1);
int len = strlen(s + 1);
cnt = tail = 1;
pos[1] = &tree[1]; tot = 1;
for(int i = 1; i <= len; i ++) insert(s[i] - 'A' + 1);
char qt[10];
int mask = 0;
for(int i = 1; i <= n; i ++){
scanf("%s%s", qt, s);
int len = strlen(s);
for(int _mask = mask, j = 0; j < len; j ++){
_mask = (_mask * 131 + j) % len;
swap(s[_mask], s[j]);
}
if(qt[0] == 'A'){
// tail = 1;
for(int j = 0; j < len; j ++) insert(s[j] - 'A' + 1);
}
else{
int t = 1, ans = 0;
for(int j = 0; j < len; j ++){
t = a[t].tranc[s[j] - 'A' + 1];
}
if(t) ans = getans(pos[t]);
printf("%d\n", ans);
mask ^= ans;
}
}
return 0;
}
BZOJ2555——SubString的更多相关文章
- BZOJ2555 SubString【SAM + Link Cut Tree】
BZOJ2555. SubString 要求在线询问一个串在原串中出现的次数,并且可以在原串末尾添加字符串 如果没有修改的话,考虑建出\(parent\)树之后统计每个\(endpos\)节点的\(r ...
- [BZOJ2555]SubString LCT+后缀自动机
2555: SubString Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 3253 Solved: 975[Submit][Status][Di ...
- bzoj2555: SubString
SAM+LCT维护parent tree版本 虽然说子树维护那套理论需要ETT 不过parent tree的根是固定的,所以用lct加一些奇怪的乱搞就行了 //随手拖个SAM的板子和LCT的板子,然后 ...
- 2019.03.01 bzoj2555: SubString(sam+lct)
传送门 题意简述: 要求在线支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 思路: 考虑用lctlctlct来动态维护samsa ...
- bzoj2555: SubString sam+lct
题意:懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支持这些操作. 题解 ...
- bzoj2555 substring(LCT 后缀自动机)
/* 动态求right集合的大小 LCT维护parent树即可 注意 由于树是有向的不会换根并且每次操作单一, 于是不需要维护子树和(写起来很麻烦) 直接打标记修改即可 */ #include< ...
- bzoj千题计划285:bzoj2555: SubString
http://www.lydsy.com/JudgeOnline/problem.php?id=2555 后缀自动机,用LCT维护parent树 一个串的出现次数 = parent 树 上 其所在状态 ...
- BZOJ2555 SubString【后缀自动机+LCT】
Description 懒得写背景了,给你一个字符串init,要求你支持两个操作 (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 你必须在线支 ...
- luogu5212/bzoj2555 substring(后缀自动机+动态树)
对字符串构建一个后缀自动机. 每次查询的就是在转移边上得到节点的parent树中后缀节点数量. 由于强制在线,可以用动态树维护后缀自动机parent树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...
随机推荐
- Docker入门教程(四)Docker Registry
Docker入门教程(四)Docker Registry [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第四篇,介绍了Docker Registry,它 ...
- DNS介绍
DNS出现及演化 网络出现的早期 是使用IP地址通讯的,那时就几台主机通讯.但是随着接入网络主机的增多,这种数字标识的地址非常不便于记忆,UNIX上就出现了建立一个叫做hosts的文件(Linux和w ...
- electron打包
1.全局安装electron-packager npm install -g electron-packager 2.在项目目录下执行命令 electron-packager ./ --platfor ...
- HTML学习笔记——块级标签、行级标签、图片标签
1>块级标签.行级标签 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "htt ...
- JSP EL表达式
1 EL表达式简介 EL 全名为Expression Language.EL主要作用: 1.获取数据 EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象.获取数 ...
- ecshop登录
邮箱登录 a.找到function login(){} ,增加一个邮箱判断is_mail() , b.如果通过,增读取出username , c.再通过默认的login功能 1.需要修改文件incl ...
- yourphp的edit,updata,dele
参考文件Yourphp\Lib\Action\User\PostAction.class.php public function add() { $form=new Form(); $form-> ...
- Robot Framework--04 工作区
转自:http://blog.csdn.net/tulituqi/article/details/7592711 一:Edit 接着前面的来,重新打开我们的RIDE,你会发现之前最后加的Resourc ...
- GoLang之基础
GoLang之基础 Go是一种并发的.带垃圾回收的.快速编译的语言. 经典的"hello world"入门: package main import "fmt" ...
- PHP任意文件包含绕过截断新姿势
前言 此方法是@l3m0n叔叔给我分享的,原文已经发布在90sec 我没有90sec的账号,所以自己实践一下,顺道安利给访问我博客的小伙伴. 适用情况 可以控制协议的情况下,如果%00无法截断包含,可 ...