[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,我们将这个 ...
随机推荐
- OGG-01224 Bad file number
今天在看OGG的日志时.发现例如以下OGG-01224 Bad file number错误.查阅资料才知道port不可用,看了一下mgr的參数,发现是设置的DYNAMICPORTLIST 动态port ...
- MySQL源码:索引相关的数据结构
http://www.orczhou.com/index.php/2012/11/mysql-source-code-data-structure-about-index/ 本文将尝试介绍MySQL索 ...
- java与javax有什么区别?
java 是java j2sdk 中的类库,也就是Java Development kit . 它提供也一些基础的东西,如io库.桌面程序的类库,如awt.集合库(如Collection.List.M ...
- linux ptrace II
第一篇 linux ptrace I 在之前的文章中我们用ptrace函数实现了查看系统调用参数的功能.在这篇文章中,我们会用ptrace函数实现设置断点,跟代码注入功能. 参考资料 Playing ...
- request对象多种方法封装表单数据
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, ...
- Linux Bash算数运算方法小结
A= B= 方法1:let(中间无空格) let C=$A+$B 方法2:$[ ] C=$[$A+$B] 方法3:$(()) C=$(($A+$B)) 方法4:expr(中间有空格) C=`expr ...
- PHP之APC缓存详细介绍
1.APC缓存简介 APC,全称是Alternative PHP Cache,官方翻译叫"可选PHP缓存".它为我们提供了缓存和优化PHP的中间代码的框架. APC的缓存分两部分: ...
- JavaScript单例模式
一.什么是单例 意思是指获取的对象只有一份. 二.最通用的单例 任何时刻获取SingLeton.instance都是同一个对象 var SingLeton={ instance:{ property: ...
- css3 盒模型
0,前言 在css2.1 之前,我们都熟知的两种盒模型,一种是w3c标准盒模型,另外一种是怪异模式下的盒模型.在css3之前我们一直使用的是标准盒模型,但是标准盒模型的宽度总是需要小心的去使用,稍有不 ...
- Java SE (3) 之 事件监听
package com.sun; import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Demo ...