博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[JSOI2008] 火星人prefix
阅读量:5226 次
发布时间:2019-06-14

本文共 4339 字,大约阅读时间需要 14 分钟。

\(\text{Description}\)

火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:\(madamimadam\) ,我们将这个字符串的各个字符予以标号:序号: \(1 2 3 4 5 6 7 8 9 10 11\) 字符 \(m a d a m i m a d a m\) 现在,火星人定义了一个函数 \(LCQ(x, y)\) ,表示:该字符串中第 \(x\) 个字符开始的字串,与该字符串中第 \(y\) 个字符开始的字串,两个字串的公共前缀的长度。比方说,\(LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0\) 在研究 \(LCQ\) 函数的过程中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出 \(LCQ\) 函数的值;同样,如果求出了 \(LCQ\) 数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取 \(LCQ\) 函数的快速算法,但不甘心认输的地球人又给火星人出了个难题:在求取 \(LCQ\) 函数的同时,还可以改变字符串本身。具体地说,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此复杂的问题中,火星人是否还能够做到很快地求取 \(LCQ\) 函数的值。

\(\text{Input}\)

第一行给出初始的字符串。第二行是一个非负整数 \(M\) ,表示操作的个数。接下来的 \(M\) 行,每行描述一个操作。操作有 \(3\) 种,如下所示:

  1. 询问。语法:\(Q\ x\ y\)\(x, y\) 均为正整数。功能:计算 \(LCQ(x, y)\) 限制:\(1 <= x, y <= 当前字符串长度\)

  2. 修改。语法:\(R\ x\ d\)\(x\) 是正整数,\(d\) 是字符。功能:将字符串中第 \(x\) 个数修改为字符 \(d\) 。限制:\(x\) 不超过当前字符串长度。

  3. 插入:语法:\(I\ x\ d\)\(x\) 是非负整数,\(d\) 是字符。功能:在字符串第 \(x\)个字符之后插入字符 \(d\) , 如果 \(x = 0\) ,则在字符串开头插入。限制:\(x\) 不超过当前字符串长度。

\(\text{Output}\)

对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。

\(\text{Sample Input}\)

madamimadam7Q 1 7Q 4 8Q 10 11R 3 aQ 1 7I 10 aQ 2 11

\(\text{Sample Output}\)

51021

数据规模:

对于 \(100%\) 的数据,满足:

1、 所有字符串自始至终都只有小写字母构成。

2、 \(M <= 150,000\)

3、 字符串长度 \(L\) 自始至终都满足 \(L <= 100,000\)

4、 询问操作的个数不超过 \(10,000\) 个。

对于第 \(1,2\) 个数据,字符串长度自始至终都不超过 \(1,000\)

对于第 \(3,4,5\) 个数据,没有插入操作。

\(\text{Solution:}\)

维护一颗splay区间树,维护一个节点为根的子树中序遍历的字符串的哈希值。

\(LCP\) 就二分长度,然后比较。

#define ull unsigned long longconst int maxN = 5e5 + 10;const int base = 27;ull xp[maxN], H[maxN];int n, m;int fa[maxN], ch[maxN][2], val[maxN], size[maxN], Ncnt, root, sz;#define ls(x) (ch[x][0])#define rs(x) (ch[x][1])#define chk(x) (ch[fa[x]][1] == x)inline void pushup(int x) {    size[x] = size[ls(x)] + size[rs(x)] + 1;    H[x] = H[ls(x)] * xp[size[rs(x)] + 1] + val[x] * xp[size[rs(x)]] + H[rs(x)];}inline void rotate(int x) {    int y = fa[x], z = fa[y], k = chk(x), tmp = ch[x][k ^ 1];    ch[y][k] = tmp, fa[tmp] = y;    ch[z][chk(y)] = x, fa[x] = z;    ch[x][k ^ 1] = y, fa[y] = x;    pushup(y), pushup(x);}inline void splay(int x, int goal = 0) {    int y, z;    while (fa[x] != goal) {        y = fa[x], z = fa[y];        if (z != goal) {            if (chk(x) == chk(y)) rotate(y);            else rotate(x);        }        rotate(x);    }    if (goal == 0) root = x;}inline int kth(int k) {    int x = root;    while (1) {        if (ch[x][0] && k <= size[ls(x)])            x = ls(x);        else if (size[ls(x)] + 1 < k) {            k -= size[ls(x)] + 1, x = rs(x);        } else return x;    }}inline int split(int x, int y) {    int pre = kth(x - 1), nxt = kth(y + 1);    splay(pre); splay(nxt, pre);    return ls(nxt);}inline void insert(int x, char str) {    int pre = kth(x), nxt = kth(x + 1);    splay(pre); splay(nxt, pre);    int cur = ++Ncnt;    ch[nxt][0] = cur;    val[cur] = H[cur] = str - 'a' + 1;    size[cur] = 1;    fa[cur] = nxt;    splay(cur);}inline ull query(int x, int L) {    int cur = split(x, x + L - 1);    return H[cur];}inline int solve(int x, int y) {    int l = 1, r = min(sz - x, sz - y), mid, ans = 0;    while (l <= r) {        mid = (l + r) >> 1;        if (query(x, mid) == query(y, mid)) ans = mid, l = mid + 1;        else r = mid - 1;    }    return ans;}int build(int l, int r, char *cher) {    if (l > r) return 0;    int mid = (l + r) >> 1;    int x = ++Ncnt;    size[x] = 1;    val[x] = H[x] = cher[mid] - 'a' + 1;    if (ch[x][0] = build(l, mid - 1, cher)) fa[ch[x][0]] = x;    if (ch[x][1] = build(mid + 1, r, cher)) fa[ch[x][1]] = x;    pushup(x);    return x;}char str[maxN];int main() {#ifndef ONLINE_JUDGE    file("P4036");#endif    xp[0] = 1;    for (int i = 1; i < maxN; ++ i) xp[i] = xp[i - 1] * base;    scanf("%s", str + 2);    n = strlen(str + 2); sz = n + 2;    root = build(1, n + 2, str);    scanf("%d", &m);    char op[30], s[3];    while (m --) {        scanf("%s", op);        if (op[0] == 'Q') {            int x, y; scanf("%d%d", &x, &y);            printf("%d\n", solve(x + 1, y + 1));        } else if (op[0] == 'R') {            int x; scanf("%d%s", &x, s);            int cur = kth(x + 1); splay(cur);            val[cur] = s[0] - 'a' + 1;            pushup(cur);        } else {            int x; scanf("%d%s", &x, s);            insert(x + 1, s[0]);            sz++;        }    }}

转载于:https://www.cnblogs.com/cnyali-Tea/p/10545871.html

你可能感兴趣的文章
我是插件狂人,jDuang,jValidator,jModal,jGallery
查看>>
张季跃 201771010139《面向对象程序设计(java)》第四周学习总结
查看>>
如何解除循环引用
查看>>
android中fragment的使用及与activity之间的通信
查看>>
字典【Tire 模板】
查看>>
jquery的contains方法
查看>>
python3--算法基础:二分查找/折半查找
查看>>
Perl IO:随机读写文件
查看>>
Perl IO:IO重定向
查看>>
转:基于用户投票的排名算法系列
查看>>
WSDL 详解
查看>>
[转]ASP数组全集,多维数组和一维数组
查看>>
C# winform DataGridView 常见属性
查看>>
逻辑运算和while循环.
查看>>
Nhiberate (一)
查看>>
c#后台计算2个日期之间的天数差
查看>>
安卓开发中遇到的小问题
查看>>
ARTS打卡第3周
查看>>
linux后台运行和关闭SSH运行,查看后台任务
查看>>
cookies相关概念
查看>>