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树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...
随机推荐
- shell text process code
shell 命令处理文本: 1. 批量处理该目录下的文件,ls | while read l ; do echo $l ; done > b.txt 2. 批量处理文件的每一行 , cut - ...
- Yocto开发笔记之《快速入门,环境搭建 & 编译》(QQ交流群:519230208)
开了一个交流群,欢迎爱好者和开发者一起交流,转载请注明出处. QQ群:,为避免广告骚扰,申请时请注明 “开发者” 字样 ======================================== ...
- PHP中静态与抽象的概念
静态//普通成员//普通成员是属于对象的 //静态成员//静态成员属于类的 类中的静态属性非常类似于函数的全局变量.类中的静态成员是不需要对象而使用类名来直接访问的. //关键字:static//se ...
- Java Web的两种开发模式
参考文献:http://www.cnblogs.com/xdp-gacl/p/3908610.html 一.Jsp+JavaBean 此模式如下图所示:
- 面向对象编程OOP-1
在下面的例子中, 我们定义了 Student类作为 Person类的子类. 之后我们重定义了sayHello() 方法并添加了 sayGoodBye() 方法 // 定义Person构造器 funct ...
- 取出return array() 数组内容
d.php文件 return array( "0" => 内容一, "1" => 内容二, "2" => 内容三, &qu ...
- Unity 下载
Unity历史版本 http://wiki.ceeger.com/unity:history#unity_522f1 UNITY 下载存档 http://unity3d.com/cn/get-unit ...
- HTML \ XHTML \XML 的区别
虽然是很简单的知识,但如果总是在需要的时候去查找,不需要的时候就丢掉,未免心里总是觉的不踏实.因为你就像是垃圾收购站,有垃圾(知识)就往里面拖,拖不下了就丢掉一些(忘了).不去整理,也因此也不知道丢的 ...
- angularjs之自己定义指令篇
1>指令基础知识 directive() 参考资料 http://www.tuicool.com/articles/aAveEj http://damoqiongqiu.iteye.com/bl ...
- 怎么搭建Web Api
1.通常我们有个web 让后可以有个web api 提供接口2.通常我们分别建两个项目 web api 依赖web的来进行访问(说到底是依赖是IIS)3.我们先建个SmallCode.Test.Web ...