[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,我们将这个 ...
随机推荐
- [TypeScript] Understanding Decorators
Decorators are a feature of TypeScript that are becoming more and more common in many major librarie ...
- [Angular 2] 8. Better ES5 Code
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- linux下64位汇编的系统调用系列
http://blog.csdn.net/mydo/article/category/3084893
- JAVA的程序代码小细节,变量的使用,以及一些细节的面试题
package cn.hncu; public class LableDemo { public static void main(String[] args) { //demo1(); demo2( ...
- Ⅶ.AngularJS的点点滴滴-- 事件
事件(和js一样有冒泡和捕获) <html> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2 ...
- awk用法举例
awk文本分割输出工具(按列输出工具) awk [options] ' PATTERN { action } ' file1, file2, ... 内置变量: FS:field separator, ...
- ubuntu下创建c语言程序之hello world
将要学习c语言了,先记录一下在ubuntu下,使用vim创建一个最基本的hello world程序: 打开终端,使用cd命令转到操作的目录,如我在home下的program files文件内创建, 就 ...
- Lucida Grande字体无法正常显示冒号的解决方案
曾经贪图Mac OSX的UI漂亮,后来查到它用的是Lucida Grande字体,所以索性将win7也改成了那种字体,结果浏览器中的中文冒号全都显示为一个奇怪的符号.后来即使将字体设置回去也无法还原. ...
- [Mime] MimeReader--读取Mime的帮助类 (转载)
点击下载 MimeReader.rar 这个类是关于MimeReader的帮助类看下面代码吧 /// <summary> /// 类说明:Assistant /// 编 码 人:苏飞 // ...
- SQL server 跨库插入数据
1.INSERT INTO SELECT语句 语句形式为: Insert into Table2(field1,field2,...) select value1,value2,... from Ta ...