题目链接:BZOJ1014
题目大意
给出一个由小写字母构成的字符串,要求支持以下操作:插入一个字母,修改一个字母,询问从
i,j
开始的最长公共前缀。
L≤100000
,询问操作不超过
10000
个。
分析
splay + hash + 二分。恩,讲完了。
ps. 有人说hash可以让它自然溢出,但是我WA了,可能是我蒻吧;于是我把hash值改为了19260817,不仅A了,而且时限莫名+1s,蛤?
pss. 无论如何,我跑得还是太慢了,难道是我自带n倍常数?
上代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
const int MOD = 19260817;
int n, m, cnt;
int root;
#define lc(a) (T[a].ch[0])
#define rc(a) (T[a].ch[1])
#define csk(a) (rc(T[a].fa) == a)
#define makeLink(a, b, c) (T[T[a].ch[c] = b].fa = a)
struct nodeSP {
int fa, ch[2];
int val, size;
LL ha;
nodeSP() {}
} T[N];
int pw[N];
void getPw() {
pw[0] = 1LL;
for (int i = 1; i < N; i++)
pw[i] = pw[i - 1] * 26 % MOD;
}
inline void update(int a) {
if (!a) return;
T[a].ha = 0, T[a].size = T[lc(a)].size + T[rc(a)].size + 1;
if (lc(a)) T[a].ha = T[lc(a)].ha;
T[a].ha = (T[a].ha * 26 + (LL)T[a].val) % MOD;
if (rc(a)) T[a].ha = (T[a].ha * pw[T[rc(a)].size] + T[rc(a)].ha) % MOD;
}
int search(int a, int now) {
if (T[lc(now)].size == a - 1) return now;
else if (T[lc(now)].size > a - 1 ) return search(a, lc(now));
else return search(a - T[lc(now)].size - 1, rc(now));
}
inline void rotate(int a) {
int c = csk(a), f = T[a].fa;
makeLink(f, T[a].ch[c ^ 1], c);
if (!T[f].fa) T[a].fa = 0;
else makeLink(T[f].fa, a, csk(f));
makeLink(a, f, c ^ 1), update(f), update(a);
}
void splay(int a, int gol) {
while (T[a].fa != gol) {
if (T[T[a].fa].fa != gol) {
if (csk(a) == csk(T[a].fa)) rotate(T[a].fa);
else rotate(a);
} rotate(a);
}
if (!T[a].fa) root = a;
}
char ss[N];
void init() {
scanf("%s %d", ss + 2, &m);
update(1), n = strlen(ss + 2);
for (int i = 2; i <= n + 1; i++) {
T[i].val = ss[i] - 'a';
makeLink(i, i - 1, 0), update(i);
} makeLink(n + 2, n + 1, 0), update(root = cnt = n + 2);
}
inline void modify(int a, int b) {
splay(search(a - 1, root), 0);
splay(search(a + 1, root), root);
T[lc(rc(root))].val = b;
update(lc(rc(root))), update(rc(root)), update(root);
}
inline void insert(int a, int b) {
splay(search(a, root), 0);
splay(search(a + 1, root), root);
T[++cnt].val = b, makeLink(rc(root), cnt, 0);
update(lc(rc(root))), update(rc(root)), update(root);
}
inline bool judge(int a, int b, int c) {
splay(search(a - 1, root), 0);
splay(search(a + c, root), root);
LL haa = T[lc(rc(root))].ha;
splay(search(b - 1, root), 0);
splay(search(b + c, root), root);
LL hab = T[lc(rc(root))].ha;
return haa == hab;
}
int calcLCQ(int a, int b) {
if (a > b) swap(a, b);
int l = 1, r = cnt - b;
int mid = 0, ans = 0;
while (l <= r) {
mid = (l + r) >> 1;
if (!judge(a, b, mid)) r = mid - 1;
else l = (ans = mid) + 1;
}
return ans;
}
void figure() {
getPw();
int a, b;
for (int i = 1; i <= m; i++) {
scanf("%s", ss);
switch (ss[0]) {
case 'R':
scanf("%d %s", &a, ss);
modify(++a, ss[0] - 'a'); break;
case 'I':
scanf("%d %s", &a, ss);
insert(++a, ss[0] - 'a'); break;
case 'Q':
scanf("%d %d", &a, &b);
printf("%d\n", calcLCQ(++a, ++b)); break;
}
}
}
int main() {
init();
figure();
return 0;
}
感觉这道题上代码没什么意义,又没有什么细节,会写的都能A,就当是一个大常数的反面典型把。
以上