题目传送门
思路
复习一下Splay的基本(复杂)操作,字符串Hash什么的好久没写啦。
用Splay维护Hash值即可,一开始我是写双Hash的,一直TLE(自带大常数的DS),实在受不了就改成单Hash了,是能过的。
对于询问要二分一下,时间复杂度两个log。
代码
#include <bits/stdc++.h>
#define maxL 100100
#define mod 998244353
#define base 23333
using namespace std;
typedef long long LL;
int m, len, cnt, f[maxL];
struct Tnode{
Tnode *son[2], *fa;
int siz, val, Hash;
inline int Get_d(){return fa->son[1] == this;}
inline void Connect(Tnode *now, int d){(son[d] = now)->fa = this;}
inline int Lsiz(){return son[0] ? son[0]->siz : 0;}
inline int Rsiz(){return son[1] ? son[1]->siz : 0;}
inline int LHash(){return son[0] ? son[0]->Hash : 0;}
inline int RHash(){return son[1] ? son[1]->Hash : 0;}
void Up(){
int Tmp = (LL)LHash() * base % mod + val; if(Tmp >= mod) Tmp -= mod;
Hash = (LL)Tmp * f[Rsiz()] % mod + RHash(); if(Hash >= mod) Hash -= mod;
siz = Lsiz() + Rsiz() + 1;
}
}Node[maxL], *Root;
char ch[maxL], op[5];
inline Tnode *NewTnode(int v){
Node[cnt].siz = 1;
Node[cnt].val = v;
return Node+cnt++;
}
Tnode *Build(Tnode *last, int L, int R){
if(L > R) return NULL;
int mid = (L + R) >> 1, val = 0;
if(mid >= 1 && mid <= len) val = ch[mid-1] - 'a';
Tnode *now = NewTnode(val);
now->fa = last;
now->son[0] = Build(now, L, mid-1);
now->son[1] = Build(now, mid+1, R);
now->Up();
return now;
}
inline void Zig(Tnode *now, Tnode *&tag){
Tnode *last = now->fa;
int d = now->Get_d();
if(now->son[!d]) last->Connect(now->son[!d], d);
else last->son[d] = NULL;
if(last != tag) last->fa->Connect(now, last->Get_d());
else now->fa = tag->fa, tag = now;
now->Connect(last, !d);
last->Up();
}
void Splay(Tnode *now, Tnode *&tag){
Tnode *last;
while(now != tag){
last = now->fa;
if(last != tag) (last->Get_d() ^ now->Get_d()) ? Zig(now, tag) : Zig(last, tag);
Zig(now, tag);
}
now->Up();
}
void Work(Tnode *now, int s, Tnode *&tag){
if(!now) return;
int Lsiz = now->Lsiz() + 1;
if(Lsiz == s) Splay(now, tag);
else if(Lsiz < s) Work(now->son[1], s-Lsiz, tag);
else Work(now->son[0], s, tag);
}
inline int Query(int x, int y){
int v, w;
int L = 0, R = len - max(x, y) + 2;
while(L + 1 < R){
int mid = (L + R) >> 1;
Work(Root, x, Root);
Work(Root, x+mid+1, Root->son[1]);
v = Root->son[1]->son[0]->Hash;
Work(Root, y, Root);
Work(Root, y+mid+1, Root->son[1]);
w = Root->son[1]->son[0]->Hash;
if(v == w) L = mid;
else R = mid;
}
return L;
}
inline void Update(int x, int v){
Work(Root, x+1, Root);
Root->val = v;
Root->Up();
}
inline void Insert(int x, int v){
len ++;
Work(Root, x+1, Root);
Work(Root, x+2, Root->son[1]);
Root->son[1]->Connect(NewTnode(v), 0);
Root->son[1]->son[0]->Up();
Root->son[1]->Up();
Root->Up();
}
int Read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ '0'), c = getchar();
return x;
}
void Print(int x){
if(x > 9) Print(x / 10);
putchar(x % 10 + '0');
}
int main(){
scanf("%s", ch);
len = strlen(ch);
f[0] = 1;
for(int i = 1; i < maxL; i++) f[i] = (LL)f[i-1] * base % mod;
Root = Build(NULL, 0, len+1);
m = Read();
int x, y;
for(int i = 1; i <= m; i++){
scanf("%s", op);
if(op[0] == 'Q'){
x = Read(); y = Read();
Print(Query(x, y));
putchar('\n');
}
else if(op[0] == 'R'){
x = Read();
scanf("%s", op);
Update(x, op[0]-'a');
}
else{
x = Read();
scanf("%s", op);
Insert(x, op[0]-'a');
}
}
return 0;
}