P4036 [JSOI2008]火星人 题解

Description

Luogu传送门

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\_ \]

posted @ 2021-12-25 14:32  xixike  阅读(39)  评论(0编辑  收藏  举报