P4036 [JSOI2008]火星人 解题报告

Description

给定一个初始的字符串 sm 次操作。
- 给定x,y,求出 s[x:n]s[y:n] 的最长公共前缀。
- 给定x,d,将 s 位置 x 的字符改为 d
- 给定x,d,在 s 位置 x 后加入一个字符 d

Solution

求最长公共前缀可以用二分 + 字符串hash。

问题转化为维护 hash 值。

序列操作,想到平衡树。这里我用的是 Splay。

~~其实是个 平衡树维护hash板题了。~~

Code

复制代码
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
inline int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -f; c = getchar();}
    while (c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}
    return x * f;
}
const int N = 1e6 + 10, base = 233;
int n, m;
ull pw[N];
char s[N]; 
namespace Splay {
    int rt, tot, val[N], sz[N], fa[N], ch[N][2];
    ull hs[N];
    inline void maintain(int x) {
        sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
        hs[x] = hs[ch[x][0]] + val[x] * pw[sz[ch[x][0]]] + hs[ch[x][1]] * pw[sz[ch[x][0]] + 1];
    }
    inline bool get(int x) {return x == ch[fa[x]][1];}
    inline void rotate(int x) {
        int y = fa[x], z = fa[y], chk = get(x);
        ch[y][chk] = ch[x][chk^1];
        if (ch[x][chk^1]) fa[ch[x][chk^1]] = y;
        ch[x][chk^1] = y; fa[y] = x; fa[x] = z;
        if (z) ch[z][y == ch[z][1]] = x;
        maintain(y); maintain(x);
    } 
    inline void build(int l, int r, int x) {
        if (l > r) return;
        int mid = l + r >> 1;
        if (mid >= x) ch[x][1] = mid;
        else ch[x][0] = mid;
        fa[mid] = x; sz[mid] = 1; 
        if (l == r) return;
        build(l, mid-1, mid); build(mid+1, r, mid); 
        maintain(mid); return;  
    }
    inline void splay(int x, int goal) {
        for (int f; (f = fa[x]) != goal; rotate(x)) 
            if (fa[f] != goal) rotate(get(x) == get(f) ? f : x);
        if (!goal) rt = x;
    }
    inline int find(int x) {
        int p = rt;
        while (1) {
            if (sz[ch[p][0]] + 1 == x) return p;
            if (sz[ch[p][0]] + 1 < x) x -= sz[ch[p][0]] + 1, p = ch[p][1];
            else p = ch[p][0];  
        }
    }
    inline ull get_hash(int l, int r) {
        int x = find(l), y = find(r + 2);
        splay(x, 0); splay(y, rt);
        return hs[ch[ch[rt][1]][0]];
    }
}
using namespace Splay;
int main () {
    scanf("%s", s + 1); n = strlen(s + 1); m = read();
    pw[0] = 1; for (int i = 1; i <= n+m; ++ i) pw[i] = pw[i-1] * base; 
    for (int i = 2; i <= n + 1; ++ i) hs[i] = val[i] = s[i-1] - 'a' + 1;
    build(1, n+2, 0); rt = (n+3) >> 1; tot = n + 2;
    while (m --) {
        char opt; scanf(" %c", &opt);
        if (opt == 'Q') {
            int x = read(), y = read();
            if (x > y) swap(x, y);
            int l = 0, r = tot - y - 1, ans = 0;
            while (l <= r) {
                int mid = l + r >> 1;
                if (get_hash(x, x + mid - 1) == get_hash(y, y + mid - 1)) ans = mid, l = mid + 1;
                else r = mid - 1;
            }
            printf("%d\n", ans);
        } else if (opt == 'R') {
            int x = read(); char d; scanf(" %c", &d);
            splay(find(x + 1), 0); val[rt] = d - 'a' + 1; maintain(rt);
        } else if (opt == 'I') {
            int p = read(); char d; scanf(" %c", &d);
            int x = find(p+1), y = find(p+2);
            splay(x, 0); splay(y, rt);
            ch[ch[rt][1]][0] = ++ tot; 
            fa[tot] = ch[rt][1]; val[tot] = hs[tot] = d - 'a' + 1;
            splay(tot, 0);
        }
    }
    return 0;
}
View Code
复制代码

 

posted @   LikC1606  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示