算是陳題了吧, 至少我都在兩個oj上都見過類似題目了, 最大的特徵就是查詢一個動態字符串某兩個後綴
的最長公共前綴, 做法就是用伸展樹動態維護區間的hash值, 每次查詢時二分答案, 然後每次判斷也是
log(n), 所以查詢的複雜度是log(n) ^ 2,其他操作都是log(n)。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <cstdlib>
#include <map>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 250005 << 1;
typedef long long LL;
const int seed = 31;
LL xp[N];
char str[N];
void init() {
xp[0] = 1;
for (int i = 1; i < N; i++)
xp[i] = xp[i - 1] * seed;
}
struct Splay {
struct Node {
Node* ch[2], * fa;
LL h[2];
char val;
int sz;
bool flip;
void init(char v, Node* f, Node* x) {
fa = f;
val = v;
h[0] = h[1] = v - 'a' + 1;
flip = 0;
sz = 1;
ch[1] = ch[0] = x;
}
}D[N];
Node* null, * root, * it;
void init(int n) {
null = new Node;
null->sz = 0;
null->ch[0] = null->ch[1] = null;
null->fa = null;
null->h[1] = null->h[0] = 0;
null->flip = 0;
null->val = 0;
it = D;
it->init(0, null, null);
root = it++;
it->init(0, root, null);
root->ch[1] = it++;
for (int i = 1; i <= n; i++) {
insert(i, str[i - 1]);
}
}
void push_down(Node* rt) {
if (rt->flip) {
update(rt->ch[0]);
update(rt->ch[1]);
rt->flip = 0;
}
}
void update(Node* rt) {
if (rt == null) return;
rt->flip ^= 1;
swap(rt->ch[0], rt->ch[1]);
swap(rt->h[0], rt->h[1]);
}
void push_up(Node* rt) {
rt->sz = rt->ch[0]->sz + rt->ch[1]->sz + 1;
rt->h[0] = rt->ch[1]->h[0] + (rt->val - 'a' + 1) * xp[rt->ch[1]->sz] + rt->ch[0]->h[0] * xp[rt->ch[1]->sz + 1];
rt->h[1] = rt->ch[0]->h[1] + (rt->val - 'a' + 1) * xp[rt->ch[0]->sz] + rt->ch[1]->h[1] * xp[rt->ch[0]->sz + 1];
}
void rotate(Node *x, int d) {
Node *y = x->fa;
push_down(y), push_down(x);
y->ch[d ^ 1] = x->ch[d];
if (x->ch[d] != null) x->ch[d]->fa = y;
x->fa = y->fa;
if (y->fa != null) {
if (y->fa->ch[0] == y)
y->fa->ch[0] = x;
else
y->fa->ch[1] = x;
}
x->ch[d] = y, y->fa = x;
push_up(y);
if (y == root) root = x; // root 表示整棵樹的根結點
}
void splay(Node *x, Node *f) {
for (push_down(x); x->fa != f; ) {
if (x->fa->fa == f) // 父結點的父親即爲f,執行單旋轉
if (x->fa->ch[0] == x)
rotate(x, 1);
else
rotate(x, 0);
else {
Node *y = x->fa, *z = y->fa;
if (z->ch[0] == y)
if (y->ch[0] == x)
rotate(y, 1), rotate(x, 1);
else
rotate(x, 0), rotate(x, 1);
else
if (y->ch[1] == x)
rotate(y, 0), rotate(x, 0);
else
rotate(x, 1), rotate(x, 0);
}
}
push_up(x);
if (f == null) root = x;
}
/*
void select(int k, Node *f) {
Node *t;
for (t = root; t != null; ) {
push_down(t);
int tmp = t->ch[0]->sz + 1;
if (k == tmp) break;
if (k < tmp)
t = t->ch[0];
else
k -= tmp + 1, t = t->ch[1];
}
splay(t, f);
}*/
void insert(int p, char c) {
select(p, null);
select(p + 1, root);
it->init(c, root->ch[1], null);
root->ch[1]->ch[0] = it++;
splay(root->ch[1]->ch[0], null);
}
void replace(int p, char c) {
select(p - 1, null);
select(p + 1, root);
Node* t = root->ch[1]->ch[0];
t->val = c;
t->h[0] = t->h[1] = c - 'a' + 1;
splay(t, null);
}
LL get_hash(int p1, int p2) {
select(p1 - 1, null);
select(p2 + 1, root);
return root->ch[1]->ch[0]->h[0];
}
void reverse(int p1, int p2) {
select(p1 - 1, null);
select(p2 + 1, root);
update(root->ch[1]->ch[0]);
splay(root->ch[1], null);
}
void select(int k, Node *f) {
Node *x = root;
while(x != null) {
push_down(x);
int tmp = x->ch[0]->sz + 1;
if(k == tmp) break;
else if(k > tmp) k -= tmp, x= x->ch[1];
else x = x->ch[0];
}
splay(x, f);
}
int lcp(int p1, int p2) {
int L = 1, R = root->sz - max(p1, p2);
while (L <= R) {
int mid = L + R >> 1;
if (get_hash(p1, p1 + mid - 1) == get_hash(p2, p2 + mid - 1))
L = mid + 1;
else
R = mid - 1;
}
return R;
}
}T;
int main() {
int n, m, p1, p2, c, flag;
int test;
scanf("%d", &test);
char s[3], op[3];
init();
while (test--) {
scanf("%s%d", str, &m);
n = strlen(str);
T.init(n);
for (int i = 0; i < m; i++) {
scanf("%s", op);
if (op[0] == 'I') {
scanf("%d%s", &p1, s);
p1++;
T.insert(p1, s[0]);
}
else if (op[0] == 'R') {
scanf("%d%s", &p1, s);
p1++;
T.replace(p1, s[0]);
}
else if (op[0] == 'Q') {
scanf("%d%d", &p1, &p2);
p1++, p2++;
printf("%d\n", T.lcp(p1, p2));
}
}
}
return 0;
}