您的位置:首页 > 其它

[BZOJ]2555 Substring 后缀自动机&LCT

2017-12-12 16:04 495 查看

2555: SubString

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 3115  Solved: 925

[Submit][Status][Discuss]

Description

  

    懒得写背景了,给你一个字符串init,要求你支持两个操作

    

    (1):在当前字符串的后面插入一个字符串

    

    (2):询问字符串s在当前字符串中出现了几次?(作为连续子串)

    

    你必须在线支持这些操作。

    

Input

    第一行一个数Q表示操作个数

    

    第二行一个字符串表示初始字符串init

    

    接下来Q行,每行2个字符串Type,Str 

    

    Type是ADD的话表示在后面插入字符串。

    

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

    

    为了体现在线操作,你需要维护一个变量mask,初始值为0

   


    

    读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。

    询问的时候,对TrueStr询问后输出一行答案Result

    然后mask = mask xor Result  

    插入的时候,将TrueStr插到当前字符串后面即可。

HINT:ADD和QUERY操作的字符串都需要解压

   

Output

Sample Input

2

A

QUERY B

ADD BBABBBBAAB

Sample Output

0

HINT

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

    

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

新加数据一组--2015.05.20

   

Source

Ctsc模拟赛By 洁妹

[Submit][Status][Discuss]

HOME Back

  hh代码题...要求动态插入当然是用sam啦... 由sam里的parent的性质可以得到, 一个串的出现次数就是在sam里面跑出来到的节点的在parent树里的子树siz, 也就是到达点的 |right|. 由于要动态插入并且sam中会有砍掉par边, 加入par边的操作... 于是就想到用lct来维护啦. 这道题是有向图都不用makeroot... 虽然说是代码题但还是挺好写的, 也就100行.

  需要注意的细节: 在访问一个节点的w一定要记得先把标记传下来, 要不然就会得到错误的答案。 话说样例查询不存在的串, 加了串后又不查询是有多水? 不过还是帮我查出re233. 一发AC一颗赛艇.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 5;
string chars;
char ss[maxn];
int top, root, tot, mask, last, Q, ans;
int dep[maxn], w[maxn], tag[maxn], c[maxn][2], fa[maxn], s[maxn], a[maxn][26], par[maxn];
inline void decr(int mask) {
scanf("%s", ss);
chars = ss;
for (int j = 0; j < chars.length(); ++ j) {
mask = (mask * 131 + j) % chars.length();
char t = chars[j];
chars[j] = chars[mask];
chars[mask] = t;
}
}
inline bool isroot(const int &x) {
return c[fa[x]][0] != x && c[fa[x]][1] != x;
}
inline void add(int x, int val) {
if (x) w[x] += val, tag[x] += val;
}

inline void pushdown(int x) {
if (tag[x]) {
add(c[x][0], tag[x]), add(c[x][1], tag[x]);
tag[x] = 0;
}
}
inline void rotate(int x) {
int y = fa[x], z = fa[y];
int l = (c[y][1] == x), r = l ^ 1;
if (!isroot(y)) c[z][c[z][1] == y] = x;
fa[x] = z, fa[y] = x, fa[c[x][r]] = y;
c[y][l] = c[x][r], c[x][r] = y;
}
inline void splay(int x) {
top = 0;
s[++ top] = x;
for (int i = x; !isroot(i); i = fa[i]) s[++ top] = fa[i];
for (int i = top; i; -- i) pushdown(s[i]);
for (int f; !isroot(x); rotate(x))
if (!isroot(f = fa[x]))
rotate((c[fa[f]][0] == f ^ c[f][0] == x) ? x : f);
}
inline void access(int x) {
for (int t = 0; x; x = fa[x])
splay(x), c[x][1] = t, t = x;
}
inline void link(int x, int y) {
fa[x] = y, access(y), splay(y), add(y, w[x]);
}
inline void cut(int x) {
access(x), splay(x), add(c[x][0], -w[x]);
fa[c[x][0]] = 0, c[x][0] = 0;
}
inline int query() {
decr(mask);
int len = chars.length(), p = 1;
for (int j = 0; j < len; ++ j)
if (!(p = a[p][chars[j] - 'A'])) return 0;
splay(p);
return w[p];
}
inline void insert(int c) {
int p = last, np = last = ++ tot;
w[np] = 1, dep[np] = dep[p] + 1;
while (p && !a[p][c]) a[p][c] = np, p = par[p];
if (!p) par[np] = root, link(np, root);
else {
int q = a[p][c];
if (dep[q] == dep[p] + 1) par[np] = q, link(np, q);
else {
int nq = ++ tot;
dep[nq] = dep[p] + 1;
par[nq] = par[q], link(nq, par[q]);
memcpy(a[nq], a[q], sizeof(a[q]));
par[np] = par[q] = nq;
cut(q), link(q, nq), link(np, nq);
while (a[p][c] == q) a[p][c] = nq, p = par[p];
}
}
}
int main() {
root = last = ++ tot;
scanf("%d", &Q);
scanf("%s", ss);
for (register int i = 0; ss[i]; ++ i)
insert(ss[i] - 'A');
for (register int i = 0; i < Q; ++ i) {
scanf("%s", ss);
if (ss[0] == 'A') {
decr(mask);
int len = chars.length();
for (int j = 0; j < len; ++ j)
insert(chars[j] - 'A');
} else {
ans = query(), mask ^= ans;
printf("%d\n", ans);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: