[BZOJ 1014] [JSOI2008] 火星人prefix 【Splay + Hash】
题目链接:BZOJ - 1014
题目分析
求两个串的 LCP ,一种常见的方法就是 二分+Hash,对于一个二分的长度 l,如果两个串的长度为 l 的前缀的Hash相等,就认为他们相等。
这里有修改字符和插入字符的操作,所以用 Splay 来维护串的 Hash 值。
一个节点的值就是它的子树表示的字串的 Hash 值。
使用 unsigned long long 然后自然溢出就不需要 mod 了,速度会快很多。
代码
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm> using namespace std; inline int gmax(int a, int b) {return a > b ? a : b;} typedef unsigned long long ULL; const ULL Seed = 211; const int MaxN = 100000 + 5; int n, l, m, Root, Index;
int Father[MaxN], Son[MaxN][2], Size[MaxN]; ULL H[MaxN], Pow_Seed[MaxN]; char Str[MaxN], T[MaxN]; int NewNode(char c)
{
int x = ++Index;
T[x] = c;
H[x] = (ULL)c;
Size[x] = 1;
return x;
} inline void Update(int x)
{
Size[x] = Size[Son[x][0]] + Size[Son[x][1]] + 1;
H[x] = (H[Son[x][0]] * Seed + T[x]) * Pow_Seed[Size[Son[x][1]]] + H[Son[x][1]];
} int Build(int s, int t)
{
int x, m = (s + t) >> 1;
x = NewNode(Str[m]);
if (s < m)
{
Son[x][0] = Build(s, m - 1);
Father[Son[x][0]] = x;
}
if (t > m)
{
Son[x][1] = Build(m + 1, t);
Father[Son[x][1]] = x;
}
Update(x);
return x;
} inline int GetDir(int x)
{
if (x == Son[Father[x]][0]) return 0;
else return 1;
} void Rotate(int x)
{
int y = Father[x], f = GetDir(x) ^ 1;
Father[x] = Father[y];
if (Father[y])
{
if (y == Son[Father[y]][0]) Son[Father[y]][0] = x;
else Son[Father[y]][1] = x;
}
Son[y][f ^ 1] = Son[x][f];
if (Son[x][f]) Father[Son[x][f]] = y;
Son[x][f] = y;
Father[y] = x;
Update(y); Update(x);
} void Splay(int x, int d)
{
int y;
while (Father[x] != d)
{
y = Father[x];
if (Father[y] == d)
{
Rotate(x);
break;
}
if (GetDir(y) == GetDir(x)) Rotate(y);
else Rotate(x);
Rotate(x);
}
if (Father[x] == 0) Root = x;
} int Find(int Num)
{
int x = Root, k = Num;
while (Size[Son[x][0]] + 1 != k)
{
if (Size[Son[x][0]] + 1 > k)
x = Son[x][0];
else
{
k -= Size[Son[x][0]] + 1;
x = Son[x][1];
}
}
return x;
} bool Check(int p, int q, int len)
{
if (len == 0) return true;
int x, y;
ULL Hp, Hq;
x = Find(p);
y = Find(p + len + 1);
Splay(x, 0);
Splay(y, x);
Hp = H[Son[y][0]];
x = Find(q);
y = Find(q + len + 1);
Splay(x, 0);
Splay(y, x);
Hq = H[Son[y][0]]; return Hp == Hq;
} int main()
{
Pow_Seed[0] = 1;
for (int i = 1; i <= 100000; ++i)
Pow_Seed[i] = Pow_Seed[i - 1] * Seed;
scanf("%s", Str + 1);
l = strlen(Str + 1);
n = l;
Root = Build(0, l + 1);
scanf("%d", &m);
char f, ch;
int Pos, x, y, p, q, l, r, mid, Ans;
for (int i = 1; i <= m; ++i)
{
f = '-';
while (f < 'A' || f > 'Z') f = getchar();
switch (f)
{
case 'R' :
scanf("%d %c", &Pos, &ch);
x = Find(Pos + 1);
Splay(x, 0);
T[x] = ch;
H[x] = (ULL)ch;
Update(x);
break; case 'I' :
++n;
scanf("%d %c", &Pos, &ch);
x = Find(Pos + 1);
y = Find(Pos + 2);
Splay(x, 0);
Splay(y, x);
Son[y][0] = ++Index;
T[Index] = ch;
H[Index] = (ULL)ch;
Size[Index] = 1;
Father[Index] = y;
Update(y); Update(x);
break; case 'Q' :
scanf("%d%d", &p, &q);
l = 0; r = n - gmax(p, q) + 1;
while (l <= r)
{
mid = (l + r) >> 1;
if (Check(p, q, mid))
{
Ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
printf("%d\n", Ans);
break;
}
}
return 0;
}
[BZOJ 1014] [JSOI2008] 火星人prefix 【Splay + Hash】的更多相关文章
- BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )
用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long ...
- BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8112 Solved: 2569[Submit] ...
- BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6243 Solved: 2007[Submit] ...
- BZOJ 1014: [JSOI2008]火星人prefix Splay+二分
1014: [JSOI2008]火星人prefix 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1014 Description 火星人 ...
- BZOJ 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)
题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度 乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾) 看题解才知道这是一道splay题,首先要对s ...
- bzoj 1014 [JSOI2008]火星人prefix——splay+哈希
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 用splay维护字符串,每个点记录子树的哈希值,然后二分查询. 二分不是把两个点的哈希 ...
- BZOJ 1014 [JSOI2008]火星人prefix | Splay维护哈希值
题目: 题解: #include<cstdio> #include<algorithm> #include<cstring> typedef long long l ...
- bzoj 1014: [JSOI2008]火星人prefix hash && splay
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3154 Solved: 948[Submit][ ...
- 求帮看!!!!BZOJ 1014 [JSOI2008]火星人prefix
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4164 Solved: 1277[Submit] ...
- 【BZOJ1014】[JSOI2008]火星人prefix Splay+hash
[BZOJ1014][JSOI2008]火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个 ...
随机推荐
- 在Eclipse上搭建Cocos2d-x的Android开发环境
很多其它相关内容请查看本人博客:http://www.bokeyi.com/ll/category/cocos2d-x/ 本文的搭建方法是最新最正确的方法,好多朋友反映搭建eclipse交叉编译环境非 ...
- java连接oracle的简单实例
连接oracle的时候,要导入oracle驱动的jar包. 连接的时候,有statement和preparedstatement两种,从代码中可以看出不同. example: package com. ...
- android84 广播接受者
#广播接收者(广播接受者进程关闭了也能接收到广播,系统会在清单文件中找哪个广播接受者可以收到这条广播,然后去启动这个接受者的进程,找不到则广播发了就发了没人收到而已) * 现实中:电台要发布消息,通过 ...
- tty、pty、pts等(小记)
http://blog.csdn.net/dbzhang800/article/details/6939742 1> tty(终端设备的统称):tty一词源于Teletypes,或者telety ...
- 高效 jquery 的奥秘
当你准备使用 jQuery,我强烈建议你遵循下面这些指南: 1. 缓存变量 DOM 遍历是昂贵的,所以尽量将会重用的元素缓存. // 糟糕 h = $('#element').height(); $( ...
- springmvc获得项目根目录(绝对路径)
原文:http://www.bubuko.com/infodetail-790547.html 在项目中有时候我们需要记录日志或者上传图片,需要知道项目的具体路径,如果项目中使用了spring,那么获 ...
- Java重写和重载的区别
区别点 重载方法 重写方法 参数列表 必须修改 一定不能修改 返回类型 可以修改 一定不能修改 异常 可以修改 可以减少或删除,一定不能抛出新的或者更广的异常 访问 可以修改 一定不能做更严格的限制( ...
- [访问系统] Api_Win32_Mac类工具包 (转载)
点击下载 Api_Win32_Mac.zip using System; using System.Collections.Generic; using System.Linq; using Syst ...
- 第八章 CTE 递归 及 分组汇总 高级部分(多维数据集)
UNION 等集合操作符: UNION 等以第一个 SELECT 的 列明 作为 整个结果集的列明,整个结果集 唯一认可的 唯一逻辑处理阶段 是 ORDER BY 这个意思是说 只有 ORDER ...
- C#中如何正确的操作字符串?
字符串应该是所有编程语言中使用最频繁的一种基础数据类型.如果使用不慎,我们就会为一次字符串的操作所带来的额外性能开销而付出代价.本条建议将从两个方面来探讨如何规避这类性能开销: 1. 确保尽量少的装箱 ...