[BZOJ1014]火星人prefix

题目链接BZOJ1014

题目大意
给出一个由小写字母构成的字符串,要求支持以下操作:插入一个字母,修改一个字母,询问从 i,j 开始的最长公共前缀。 L100000 ,询问操作不超过 10000 个。

分析
splay + hash + 二分。恩,讲完了。
ps. 有人说hash可以让它自然溢出,但是我WA了,可能是我蒻吧;于是我把hash值改为了19260817,不仅A了,而且时限莫名+1s,蛤?
pss. 无论如何,我跑得还是太慢了,难道是我自带n倍常数?

时限+1s

上代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
const int N = 1e5 + 10;
const int MOD = 19260817;

int n, m, cnt;

int root;
#define lc(a) (T[a].ch[0])
#define rc(a) (T[a].ch[1])
#define csk(a) (rc(T[a].fa) == a)
#define makeLink(a, b, c) (T[T[a].ch[c] = b].fa = a)
struct nodeSP {
    int fa, ch[2];
    int val, size;
    LL ha;
    nodeSP() {}
} T[N];

int pw[N];
void getPw() {
    pw[0] = 1LL;
    for (int i = 1; i < N; i++)
        pw[i] = pw[i - 1] * 26 % MOD;
}
inline void update(int a) {
    if (!a) return;
    T[a].ha = 0, T[a].size = T[lc(a)].size + T[rc(a)].size + 1;
    if (lc(a)) T[a].ha = T[lc(a)].ha;
    T[a].ha = (T[a].ha * 26 + (LL)T[a].val) % MOD;
    if (rc(a)) T[a].ha = (T[a].ha * pw[T[rc(a)].size] + T[rc(a)].ha) % MOD;
}
int search(int a, int now) {
    if (T[lc(now)].size == a - 1) return now;
    else if (T[lc(now)].size > a - 1 ) return search(a, lc(now));
    else return search(a - T[lc(now)].size - 1, rc(now));
}
inline void rotate(int a) {
    int c = csk(a), f = T[a].fa;
    makeLink(f, T[a].ch[c ^ 1], c);
    if (!T[f].fa) T[a].fa = 0;
    else makeLink(T[f].fa, a, csk(f));
    makeLink(a, f, c ^ 1), update(f), update(a);
}
void splay(int a, int gol) {
    while (T[a].fa != gol) {
        if (T[T[a].fa].fa != gol) {
            if (csk(a) == csk(T[a].fa)) rotate(T[a].fa);
            else rotate(a);
        } rotate(a);
    }
    if (!T[a].fa) root = a;
}

char ss[N];
void init() {
    scanf("%s %d", ss + 2, &m);
    update(1), n = strlen(ss + 2);
    for (int i = 2; i <= n + 1; i++) {
        T[i].val = ss[i] - 'a';
        makeLink(i, i - 1, 0), update(i);
    } makeLink(n + 2, n + 1, 0), update(root = cnt = n + 2);
}
inline void modify(int a, int b) {
    splay(search(a - 1, root), 0);
    splay(search(a + 1, root), root);
    T[lc(rc(root))].val = b;
    update(lc(rc(root))), update(rc(root)), update(root);
}
inline void insert(int a, int b) {
    splay(search(a, root), 0);
    splay(search(a + 1, root), root);
    T[++cnt].val = b, makeLink(rc(root), cnt, 0);
    update(lc(rc(root))), update(rc(root)), update(root);
}
inline bool judge(int a, int b, int c) {
    splay(search(a - 1, root), 0);
    splay(search(a + c, root), root);
    LL haa = T[lc(rc(root))].ha;
    splay(search(b - 1, root), 0);
    splay(search(b + c, root), root);
    LL hab = T[lc(rc(root))].ha;
    return haa == hab;
}
int calcLCQ(int a, int b) {
    if (a > b) swap(a, b);
    int l = 1, r = cnt - b;
    int mid = 0, ans = 0;
    while (l <= r) {
        mid = (l + r) >> 1;
        if (!judge(a, b, mid)) r = mid - 1;
        else l = (ans = mid) + 1;
    }
    return ans;
}
void figure() {
    getPw();
    int a, b;
    for (int i = 1; i <= m; i++) {
        scanf("%s", ss);
        switch (ss[0]) {
            case 'R':
                scanf("%d %s", &a, ss);
                modify(++a, ss[0] - 'a'); break;
            case 'I':
                scanf("%d %s", &a, ss);
                insert(++a, ss[0] - 'a'); break;
            case 'Q':
                scanf("%d %d", &a, &b);
                printf("%d\n", calcLCQ(++a, ++b)); break;
        }
    }
}

int main() {
    init();
    figure();
    return 0;
}

感觉这道题上代码没什么意义,又没有什么细节,会写的都能A,就当是一个大常数的反面典型把。
以上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值