P4036 [JSOI2008]火星人 题解
Description
Solution
考虑使用平衡树维护 hash 值。
一个点的 sum
值表示这个点所在子树的 hash 值,那么如何更新呢?
应该还是比较简单的吧,就是:
\[左子树_{sum} \times (右子树_{siz} + 1) + 根_{val} \times 右子树_{siz} + 右子树_{sum}
\]
t[x].sum = t[ls(x)].sum * fx[t[rs(x)].siz + 1] + t[x].val * fx[t[rs(x)].siz] + t[rs(x)].sum;
再来看如何查询,设当前询问 \(x,y\)。
考虑使用二分,我们二分一个长度 \(len\),然后查询 \(x \sim x + len - 1\) 和 \(y \sim y + len - 1\) 的 hash 值是否相等,并更新长度 \(len\),重复此操作。
剩下的就看代码吧。
Code
(厌氧程序,谨慎食用)
(开 O2 会 WA 两个点,我也不知道为啥 QwQ,如果有哪位 dalao 知道欢迎在评论区里告诉我)
#include <bits/stdc++.h>
#define uint unsigned int
#define ls(x) t[x].l
#define rs(x) t[x].r
using namespace std;
namespace IO{
inline int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
inline char readc(){
char ch = getchar();
while(ch < 'a' || ch > 'z') ch = getchar();
return ch;
}
template <typename T> inline void write(T x){
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;
const int N = 2e5 + 10;
int n, m;
uint fx[N], f[N];
char s[N], op[5];
struct fhq_treap{
int val, siz, wei, l, r;
uint sum;
}t[N];
int root, tot;
inline void pushup(int x){
t[x].siz = t[ls(x)].siz + t[rs(x)].siz + 1;
t[x].sum = t[ls(x)].sum * fx[t[rs(x)].siz + 1] + t[x].val * fx[t[rs(x)].siz] + t[rs(x)].sum;
}
inline void split(int x, int k, int &a, int &b){
if(!x) return a = b = 0, void();
if(k >= t[ls(x)].siz + 1) a = x, split(rs(x), k - t[ls(x)].siz - 1, rs(x), b);
else b = x, split(ls(x), k, a, ls(x));
pushup(x);
}
inline int merge(int x, int y){
if(!x || !y) return x | y;
if(t[x].wei <= t[y].wei){
rs(x) = merge(rs(x), y);
return pushup(x), x;
}else{
ls(y) = merge(x, ls(y));
return pushup(y), y;
}
}
inline int newnode(int k){
t[++tot].val = k, t[tot].siz = 1, t[tot].wei = rand(), t[tot].sum = k;
return tot;
}
inline void insert(int k, char ch){
int a, b;
split(root, k, a, b);
root = merge(merge(a, newnode(ch - 'a' + 1)), b);
}
inline void remove(int k){
int a, b, c;
split(root, k, a, b);
split(a, k - 1, a, c);
c = merge(ls(c), rs(c));
root = merge(merge(a, c), b);
}
inline void update(int x, char ch){
remove(x), insert(x - 1, ch);
}
inline uint calc(int l, int r){
int len = r - l + 1, a, b, c;
split(root, l - 1, a, b);
split(b, len, b, c);
uint res = t[b].sum;
root = merge(merge(a, b), c);
return res;
}
inline bool check(int l, int r, int len){
uint res1 = calc(l, l + len - 1), res2 = calc(r, r + len - 1);
return res1 == res2;
}
inline int query(int x, int y){
int l = 1, r = min(n - x, n - y) + 1, res;
while(l <= r){
int mid = (l + r) >> 1;
if(check(x, y, mid)) l = mid + 1, res = mid;
else r = mid - 1;
}
return res;
}
int main(){
scanf("%s", s + 1);
n = strlen(s + 1);
fx[0] = 1;
for(int i = 1; i < N; ++i) fx[i] = fx[i - 1] * 27;
for(int i = 1; i <= n; ++i) insert(i, s[i]);
m = read();
for(int i = 1; i <= m; ++i){
scanf("%s", op);
if(op[0] == 'Q'){
int x = read(), y = read();
write(query(x, y)), puts("");
}else if(op[0] == 'R'){
int x = read();
update(x, readc());
}else{
int x = read(); ++n;
insert(x, readc());
}
}
return 0;
}
\[\_EOF\_
\]