题目链接: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】的更多相关文章

  1. BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )

    用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long ...

  2. BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 8112  Solved: 2569[Submit] ...

  3. BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6243  Solved: 2007[Submit] ...

  4. BZOJ 1014: [JSOI2008]火星人prefix Splay+二分

    1014: [JSOI2008]火星人prefix 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1014 Description 火星人 ...

  5. BZOJ 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)

    题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度 乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾) 看题解才知道这是一道splay题,首先要对s ...

  6. bzoj 1014 [JSOI2008]火星人prefix——splay+哈希

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 用splay维护字符串,每个点记录子树的哈希值,然后二分查询. 二分不是把两个点的哈希 ...

  7. BZOJ 1014 [JSOI2008]火星人prefix | Splay维护哈希值

    题目: 题解: #include<cstdio> #include<algorithm> #include<cstring> typedef long long l ...

  8. bzoj 1014: [JSOI2008]火星人prefix hash && splay

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3154  Solved: 948[Submit][ ...

  9. 求帮看!!!!BZOJ 1014 [JSOI2008]火星人prefix

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4164  Solved: 1277[Submit] ...

  10. 【BZOJ1014】[JSOI2008]火星人prefix Splay+hash

    [BZOJ1014][JSOI2008]火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个 ...

随机推荐

  1. OGG-01224 Bad file number

    今天在看OGG的日志时.发现例如以下OGG-01224 Bad file number错误.查阅资料才知道port不可用,看了一下mgr的參数,发现是设置的DYNAMICPORTLIST 动态port ...

  2. MySQL源码:索引相关的数据结构

    http://www.orczhou.com/index.php/2012/11/mysql-source-code-data-structure-about-index/ 本文将尝试介绍MySQL索 ...

  3. java与javax有什么区别?

    java 是java j2sdk 中的类库,也就是Java Development kit . 它提供也一些基础的东西,如io库.桌面程序的类库,如awt.集合库(如Collection.List.M ...

  4. linux ptrace II

    第一篇 linux ptrace I 在之前的文章中我们用ptrace函数实现了查看系统调用参数的功能.在这篇文章中,我们会用ptrace函数实现设置断点,跟代码注入功能. 参考资料 Playing ...

  5. request对象多种方法封装表单数据

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, ...

  6. Linux Bash算数运算方法小结

    A= B= 方法1:let(中间无空格) let C=$A+$B 方法2:$[  ] C=$[$A+$B] 方法3:$(()) C=$(($A+$B)) 方法4:expr(中间有空格) C=`expr ...

  7. PHP之APC缓存详细介绍

    1.APC缓存简介 APC,全称是Alternative PHP Cache,官方翻译叫"可选PHP缓存".它为我们提供了缓存和优化PHP的中间代码的框架. APC的缓存分两部分: ...

  8. JavaScript单例模式

    一.什么是单例 意思是指获取的对象只有一份. 二.最通用的单例 任何时刻获取SingLeton.instance都是同一个对象 var SingLeton={ instance:{ property: ...

  9. css3 盒模型

    0,前言 在css2.1 之前,我们都熟知的两种盒模型,一种是w3c标准盒模型,另外一种是怪异模式下的盒模型.在css3之前我们一直使用的是标准盒模型,但是标准盒模型的宽度总是需要小心的去使用,稍有不 ...

  10. Java SE (3) 之 事件监听

    package com.sun; import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Demo ...