• Bzoj 1014&Luogu 4036 火星人Prefix(FHQ-Treap)


    题面

    洛谷

    Bzoj

    题解

    首先,这种带修改的是不能用$SA$的,然后,我们做$SA$的题一般也能二分+$Hash$,所以不妨考虑用$FHQ-Treap$维护树,然后查询就用二分+$Hash$。

    $Hash$怎么写?

    $ hash[o]=hash[lc[o]] imes base[siz[rc[o]]+1]+val[o] imes base[siz[rc[o]]]+hash[rc[o]] $

    为什么可以这么写呢?想一想,为什么

    我们一般怎么求一颗维护序列的平衡树的原序列呢?—中序遍历

    所以嘛,一棵子树的哈希值可以转化成它左子树的哈希值+本身的值+右子树哈希值

    由于怕重复,所以可以考虑将前面两个值随便乘上一点什么东西(比如左子树或者右子树的$size$之类的)

    #include <ctime>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    
    template<typename T>
    void read(T &x) {
        int flag = 1; x = 0; char ch = getchar();
        while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
        while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
    }
    
    const int N = 3e5 + 10;
    char s[N];
    int m, len, base[N];
    int rt, tot, lc[N], rc[N], pri[N], siz[N], h[N], val[N];
    
    inline void upt(int o) {
        siz[o] = siz[lc[o]] + siz[rc[o]] + 1;
        h[o] = h[lc[o]] * base[siz[rc[o]] + 1] + val[o] * base[siz[rc[o]]] + h[rc[o]];
    }
    inline int node(int x) { siz[++tot] = 1, val[tot] = h[tot] = x, pri[tot] = rand(); return tot; }
    void split(int o, int k, int &l, int &r) {
        if(!o) { l = r = 0; return ; }
        if(siz[lc[o]] < k) l = o, split(rc[o], k - siz[lc[o]] - 1, rc[o], r);
        else r = o, split(lc[o], k, l, lc[o]);
        upt(o);
    }
    int merge(int l, int r) {
        if(!l || !r) return l + r;
        if(pri[l] < pri[r]) { rc[l] = merge(rc[l], r), upt(l); return l; }
        else { lc[r] = merge(l, lc[r]), upt(r); return r; }
    }
    inline int query(int l, int r) {
        int x, y, k, ret;
        split(rt, r, x, y), split(x, l - 1, x, k);
        ret = h[k], rt = merge(merge(x, k), y);
        return ret;
    }
    
    int main () {
        scanf("%s", s + 1), len = strlen(s + 1), srand(19260817), base[0] = 1;
        for(int i = 1; i < N; ++i) base[i] = base[i - 1] * 27;
        for(int i = 1; i <= len; ++i) rt = merge(rt, node(s[i] - 'a' + 1));
        read(m); char opt[5], ch[5]; int x, y, l, r, k;
        while(m--) {
            scanf("%s", opt), read(x);
            if(opt[0] == 'Q') {
                read(y); int L = 0, R = std::min(len - x, len - y) + 1, ret;
                while(L <= R) {
                    int mid = (L + R) >> 1;
                    if(query(x, x + mid - 1) == query(y, y + mid - 1)) ret = mid, L = mid + 1;
                    else R = mid - 1;
                } printf("%d
    ", ret);
            } else {
                scanf("%s", ch), split(rt, x, l, r), ++len;
                if(opt[0] == 'R') --len, split(l, x - 1, l, k);
                rt = merge(merge(l, node(ch[0] - 'a' + 1)), r);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    VC++中对数据类型的限制limits.h文件内容
    阿里巴巴-2015秋招研发工程师附加题
    阿里巴巴-2015秋招研发工程师附加题
    如何成为一个牛逼的程序猿
    Windows7中Java64位环境变量配置:javac不是内部命令或外部命令,也不是可运行的程序或批处理文件。
    程序员面试宝典:求十进制数字的二进制数位中包含1的个数
    程序员面试宝典:与或数值运算
    docker配置阿里云镜像
    原生JS中获取位置的方案总结
    vue项目中上拉加载和下拉刷新页面的实现
  • 原文地址:https://www.cnblogs.com/water-mi/p/10161400.html
Copyright © 2020-2023  润新知