「BZOJ 2555」SubString-后缀平衡树

给定一个字符串,要求支持两种操作,在当前字符串后加入一个字符串,询问字符串 $s$ 在当前字符串中出现了几次?

链接

BZOJ 2555

题解

此题可以用 LCT + SAM 做。但是这是一道后缀平衡树的裸题

考虑用后缀平衡树,由于后缀平衡树是往前插入字符的,所以我们只需要在询问的时候把 $s$ 反转一下就可以了。

设初始化后缀平衡树时最小字符为 $min$,最大字符为 $max$,询问的答案即为 $rank(s + (max + 1)) - rank(s + (min - 1))$,对于查找对应的 $rank$,我们直接暴力在树上比较着走就可以了,时间复杂度 $O(n \log n + |\Sigma| \log n)$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/**
* Copyright (c) 2017, xehoth
* All rights reserved.
* 「BZOJ 2555」SubString 01-09-2017
* 后缀平衡树
* @author xehoth
*/
#include <bits/stdc++.h>

namespace IO {

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin) : 0;
return s == t ? -1 : *s++;
}

template <typename T>
inline void read(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return;
c == '-' ? iosig = true : 0;
}
for (x = 0; isdigit(c); c = read()) x = x * 10 + (c ^ '0');
iosig ? x = -x : 0;
}

inline void read(char &c) {
while (c = read(), isspace(c) && c != -1)
;
}

inline int read(char *buf) {
register int s = 0;
register char c;
while (c = read(), isspace(c) && c != -1)
;
if (c == -1) {
*buf = 0;
return -1;
}
do
buf[s++] = c;
while (c = read(), !isspace(c) && c != -1);
buf[s] = 0;
return s;
}

const int OUT_LEN = 1000000;

char obuf[OUT_LEN], *oh = obuf;

inline void print(char c) {
oh == obuf + OUT_LEN ? (fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf) : 0;
*oh++ = c;
}

template <typename T>
inline void print(T x) {
static int buf[30], cnt;
if (x == 0) {
print('0');
} else {
x < 0 ? (print('-'), x = -x) : 0;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 | 48;
while (cnt) print((char)buf[cnt--]);
}
}

inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); }

struct InputOutputStream {
template <typename T>
inline InputOutputStream &operator>>(T &x) {
read(x);
return *this;
}

template <typename T>
inline InputOutputStream &operator<<(const T &x) {
print(x);
return *this;
}

~InputOutputStream() { flush(); }
} io;
}

namespace {

using IO::io;

const int MAXN = 3000005;
const double ALPHA = 0.75;

struct Node {
Node *c[2];
double v;
int id, size;

Node();

Node(double v, int id);

inline void maintain() { size = c[0]->size + c[1]->size + 1; }

inline bool check() {
return std::max(c[0]->size, c[1]->size) > size * ALPHA;
}

inline void *operator new(size_t);
} pool[MAXN + 1], *null = pool, *cur = pool + 1;

Node::Node() {
c[0] = null;
c[1] = null;
id = 0;
v = 0;
size = 0;
}

Node::Node(double v, int id) {
c[0] = null;
c[1] = null;
this->v = v;
this->id = id;
this->size = 1;
}

inline void *Node::operator new(size_t) { return cur++; }

struct SuffixBalancedTree {
Node *root, *pos[MAXN + 1];

int n;

inline void init() {
root = new Node(0.5, 0);
pos[0] = root;
s[0] = 'A' - 1;
for (register int i = 1; i <= n; i++) insert(i);
}

double badL, badR;

char s[MAXN + 1], qs[MAXN + 1];

int qlen, last;

inline bool cmpSuffix(int a, int b) {
return s[a] < s[b] || (s[a] == s[b] && pos[a - 1]->v < pos[b - 1]->v);
}

inline Node **insert(Node *&p, double l, double r, int id) {
if (p == null) {
pos[id] = p = new Node((l + r) / 2, id);
return &null;
} else {
p->size++;
Node **res = cmpSuffix(id, p->id)
? insert(p->c[0], l, (l + r) / 2, id)
: insert(p->c[1], (l + r) / 2, r, id);

if (p->check()) res = &p, badL = l, badR = r;
return res;
}
}

inline void travel(Node *p, std::vector<Node *> &v) {
if (p == null) return;
travel(p->c[0], v), v.push_back(p), travel(p->c[1], v);
}

inline void dfs(Node *p) {
if (p == null) return;
dfs(p->c[0]), std::cerr << p->id << std::endl, dfs(p->c[1]);
}

inline Node *divide(std::vector<Node *> &v, int l, int r, double lv,
double rv) {
if (l >= r) return null;
register int mid = l + r >> 1;
Node *p = v[mid];
p->v = (lv + rv) / 2;
p->c[0] = divide(v, l, mid, lv, (lv + rv) / 2);
p->c[1] = divide(v, mid + 1, r, (lv + rv) / 2, rv);
p->maintain();
return p;
}

inline void rebuild(Node *&p) {
static std::vector<Node *> v;
v.clear(), travel(p, v), p = divide(v, 0, v.size(), badL, badR);
}

inline void insert(int id) {
Node **p = insert(root, 0, 1, id);
if (*p != null) rebuild(*p);
}

int mask;

inline void decode(int mask) {
qlen = IO::read(qs + 1);

char *t = qs + 1;
for (register int i = 0; i < qlen; i++) {
mask = (mask * 131 + i) % qlen;
std::swap(t[i], t[mask]);
}
}

inline int rank() {
register int ans = 1;
for (Node *p = root; p != null;) {
for (register int i = 1; i <= qlen; i++) {
if (s[p->id - i + 1] != qs[i]) {
if (s[p->id - i + 1] < qs[i]) {
ans += p->c[0]->size + 1, p = p->c[1];
break;
} else {
p = p->c[0];
break;
}
}
}
}
return ans - 2;
}

inline void query() {
if (qlen > n) {
last = 0, io << last << '\n';
mask ^= last;
return;
}
std::reverse(qs + 1, qs + qlen + 1);
qs[++qlen] = 'A' - 2;
last = -rank();
qs[qlen] = 'Z' + 2;
last += rank();
io << last << '\n';
mask ^= last;
}

inline void solve() {
register int q = 0;
io >> q;
n = IO::read(s + 1);
init();
static char cmd[10];
for (; q--;) {
io >> cmd;
decode(mask);
switch (cmd[0]) {
case 'Q':
query();
break;
case 'A':
for (register int i = 1; i <= qlen; i++)
s[++n] = qs[i], insert(n);
break;
}
}
}
} suffixBalancedTree;
}

int main() {
suffixBalancedTree.solve();
return 0;
}
#

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×