# BZOJ2555 SubString

@(XSY)[LCT]

## Description

1. 在当前字符串的后面插入一个字符串
2. 询问字符串s在当前字符串中出现了几次？(作为连续子串)
3. 你必须在线支持这些操作。

## Input

Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。

2
A
QUERY B

0

## HINT

40 % 的数据字符串最终长度 <= 20000，询问次数<= 1000，询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000，询问次数<= 10000,询问总长度<= 3000000

## Solution

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

const int LEN = 1 << 20, ORG = 'A', LIM = 1 << 5;

namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1;
char c;

while(! isdigit(c = getchar()))
if(c == '-')
sgn *= -1;

while(isdigit(c))
a = a * 10 + c - '0', c = getchar();

return a * sgn;
}

inline int getString(char *str)
{
char c;

while(! isgraph(c = getchar()));

int len = 0;

while(isgraph(c))
str[len ++] = c, c = getchar();

return len;
}
}

{
struct node
{
node *pre, *suc[2];
int w, tag, isRoot;

inline node()
{
pre = suc[0] = suc[1] = NULL;
w = tag = 0;
isRoot = 1;
}

{
if(this == NULL)
return;

tag += a, w += a;
}

inline void pushdown()
{
if(! isRoot)
pre->pushdown();

tag = 0;
}

inline int getRelation()
{
if(pre == NULL)
return -1;

return this == pre->suc[1];
}
};

inline void rotate(node *u)
{
node *pre = u->pre, *prepre = pre->pre;
int k = u->getRelation();

if(u->suc[k ^ 1] != NULL)
u->suc[k ^ 1]->pre = pre;

pre->suc[k] = u->suc[k ^ 1];
u->suc[k ^ 1] = pre;
u->pre = prepre;

prepre->suc[pre->getRelation()] = u;
else
u->isRoot = 1, pre->isRoot = 0;

pre->pre = u;
}

inline void splay(node *u)
{
u->pushdown();

while(! u->isRoot)
{
if(! u->pre->isRoot)
rotate(u->getRelation() == u->pre->getRelation() ? u->pre : u);

rotate(u);
}
}

inline void access(node *u)
{
splay(u);

while(u->pre != NULL)
{
node *pre = u->pre;
splay(pre);

if(pre->suc[1] != NULL)
pre->suc[1]->isRoot = 1;

u->isRoot = 0;
pre->suc[1] = u;
splay(u);
}
}

inline void cut(node *u)
{
access(u);

if(u->suc[0] != NULL)
u->suc[0]->pre = NULL, u->suc[0]->isRoot = 1;

u->suc[0] = NULL;
}

inline void link(node *u, node *pre)
{
cut(u);
u->pre = pre;
}
}tr;

struct suffixAutomaton
{
struct state
{
int stp;
state *pre, *suc[LIM];

inline state(int _stp = 0)
{
stp = _stp;
pre = NULL;
memset(suc, NULL, sizeof(suc));
}
};

state *s, *lst;

inline void init()
{
s = lst = new state(); //初始化时新建源点
}

{
state *p = lst, *u = new state(p->stp + 1);

for(; p != NULL && p->suc[c] == NULL; p = p->pre)
p->suc[c] = u;

if(p == NULL)
else
{
state *q = p->suc[c];

if(q->stp == p->stp + 1)
else
{
state *v = new state(p->stp + 1);
v->pre = q->pre;
memcpy(v->suc, q->suc, sizeof(q->suc));
q->pre = u->pre = v;
v->treeNode->w = q->treeNode->w;

for(; p != NULL && p->suc[c] == q; p = p->pre)
p->suc[c] = v;
}
}

lst = u;
tr.access(u->treeNode);
}

inline void insert(char *str, int len)
{
for(int i = 0; i < len; ++ i) //插入时不需要新建源点
}

inline int query(char *str, int len)
{
state *p = s;
int i;

for(i = 0; p != NULL && i < len; ++ i)
p = p->suc[str[i] - 'A'];

if(p != NULL)
{
p->treeNode->pushdown();
return p->treeNode->w;
}

return 0;
}
}org;

{
for(int i = 0; i < len; ++ i)
{
}
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj2555.in", "r", stdin);
freopen("bzoj2555.out", "w", stdout);
#endif

using namespace Zeonfai;

int q = getInt();
static char str[LEN];
int len = getString(str);
org.init();
org.insert(str, len);

while(q --)
{
char opt[1 << 4];
getString(opt);
int len = getString(str);