BZOJ_1014_[JSOI2008]_火星人prefix_(Splay+LCP_Hash+二分)
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1014
给出一个字符串,有修改,插入,以及询问LCP(i,j)的操作.
分析
LCP在白书上面有介绍,\(LCP(i,j)\)表示以第\(i\)位和以第\(j\)位开头的后缀的最长公共前缀.
先考虑没有插入和修改操作的问题.我们可以用基于Hash的LCP算法.
我们给每一个后缀一个Hash值.其中以第\(i\)为开头的后缀的Hash值为\(H[i]=H[i+1]x+s[i]\).
其中\(x\)是随便一个什么数.例如:
\(H[4]=s[4]\)
\(H[3]=s[4]x+s[3]\)
\(H[2]=s[4]x^2+s[3]x+s[2]\)
\(H[1]=s[4]x^3+s[3]x^2+s[2]x+s[1]\)
一般地有:
$$H[i]=s[n]x^{n-i}+s[n-1]x^{n-1-i}+...+s[i+1]x+s[i]$$
对于字符串\(s[i]~s[i+L-1]\)(长度为L),定义它的Hash值为:
$$Hash(i,L)=H[i]-H[i+L]x^L$$
其实就是相当于把以\(i\)开头的后缀的Hash值有关\(i+L\)以及后面的部分都砍掉.
当然这个Hash值可以定义为前缀的形式,和后缀的没有区别.
但是注意,并不是字符串不同,Hash值一定不同,只是相同的概率极低,基本可以无视.
至于计算,我们采用unsigned long long ,这样自然溢出相当于对\(2^{64}\)取模.
这样我们就可以判断字串\((i,L)\)与\((j,L)\)是否相等,二分\(L\)的值,取最大可行解即可.
至于修改和插入操作?平衡树来解决咯.平衡树上每个结点的Hash值代表的是以该结点为根的子树代表的字符串的Hash值.
p.s.
1.复习了下Splay,好不熟练啊,还要多练习,不然药丸...
2.调了好久发现是字符串读入的问题...(拍脸)
#include <bits/stdc++.h>
using namespace std; const int maxn=1e5+;
typedef unsigned long long ull;
int n,m;
ull p[maxn];
char s[maxn];
struct Splay{
struct node{
node* c[],* f;
int v,s; ull h;
node(int v,node* t):v(v){ s=;h=v;f=c[]=c[]=t; }
bool d(){ return f->c[]==this; }
void setc(node* x,bool d){ c[d]=x; x->f=this; }
void push_up(){
s=c[]->s+c[]->s+;
h=c[]->h+(ull)v*p[c[]->s]+c[]->h*p[c[]->s+];
}
}* root,* null;
Splay(){
null=new node(,);null->s=;
root=new node(,null); root->setc(new node(,null),);
}
void rot(node* x){
node* f=x->f; bool d=x->d();
f->f->setc(x,f->d());
f->setc(x->c[!d],d);
x->setc(f,!d);
f->push_up();
if(f==root) root=x;
}
void splay(node* x,node *f){
while(x->f!=f)
if(x->f->f==f) rot(x);
else x->d()==x->f->d()?(rot(x->f),rot(x)):(rot(x),rot(x));
x->push_up();
}
node* kth(int k){
for(node* t=root;t!=null;){
int s=t->c[]->s;
if(k==s) return t;
if(k>s) t=t->c[], k-=s+;
else t=t->c[];
}
}
node* get_range(int l,int r){
splay(kth(l-),null);
splay(kth(r+),root);
return root->c[]->c[];
}
void ins(int v,int pos){
node *f=get_range(pos,pos);
f->setc(new node(v,null),); splay(f->c[],null);
}
void chg(int v,int pos){
node *x=get_range(pos,pos);
x->v=v; splay(x,null);
}
int hash(int l,int r){ return get_range(l,r)->h; }
node* build(int l,int r){
if(l>r) return null;
int m=l+(r-l)/;
node *t=new node(s[m]-'a'+,null);
t->setc(build(l,m-),);
t->setc(build(m+,r),);
t->push_up();
return t;
}
}T;
inline int read(int &x){ x=;int k=;char c;for(c=getchar();c<''||c>'';c=getchar())if(c=='-')k=-;for(;c>=''&&c<='';c=getchar())x=x*+c-'';return x*=k; }
inline char read(char &c){ for(c=getchar();(c<'a'||c>'z')&&(c<'A'||c>'Z');c=getchar());return c; }
int bsearch(int x,int y){
int s=T.root->s-;
int l=,r=min(s-x,s-y)+,mid;
while(l<r){
mid=l+(r-l+)/;
if(T.hash(x,x+mid-)==T.hash(y,y+mid-)) l=mid;
else r=mid-;
}
return l;
}
void init(){
scanf("%s",s+); n=strlen(s+); read(m);
p[]=;
for(int i=;i<maxn;i++) p[i]=p[i-]*(ull);
T.root->c[]->setc(T.build(,n),); T.root->c[]->push_up(); T.root->push_up();
}
int main(){
init();
while(m--){
char c; int x,y;
read(c); read(x);
if(c=='Q'){ read(y); printf("%d\n",bsearch(x,y)); }
else if(c=='R') T.chg(read(c)-'a'+,x);
else T.ins(read(c)-'a'+,x);
}
return ;
}
BZOJ_1014_[JSOI2008]_火星人prefix_(Splay+LCP_Hash+二分)的更多相关文章
- 【bzoj1014】[JSOI2008]火星人prefix Splay+Hash+二分
题目描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 ...
- BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
1014: [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 8112 Solved: 2569[Submit] ...
- P4036 [JSOI2008]火星人(splay+hash+二分)
P4036 [JSOI2008]火星人 Splay维护hash,查询二分 $a[x].vl=a[lc].vl*ha[a[rc].sz+1]+a[x].w*ha[a[rc].sz]+a[rc].vl$ ...
- bzoj1014: [JSOI2008]火星人prefix splay+hash+二分
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解
题意不赘述了,太清晰了. 说题解:首先依据原字符串建立SPT.首尾建议多加一个空白字符. 给一个树构图,依照平衡树的前后大小顺序性质能够使它们始终维持为一个序列,而且能够通过rank找到序列的第k个. ...
- BZOJ_1014_[JSOI2008]火星人prefix_splay+hash
BZOJ_1014_[JSOI2008]火星人prefix_splay+hash 题意:火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam, 我们 ...
- 【BZOJ1014】火星人(Splay,哈希)
[BZOJ1014]火星人(Splay,哈希) 题面 BZOJ 题解 要动态维护这个串,一脸的平衡树. 那么用\(Splay\)维护这个哈希值就好了. 每次计算答案的时候二分+Splay计算区间哈希值 ...
- BZOJ_5311_贞鱼_决策单调性+带权二分
BZOJ_5311_贞鱼_决策单调性+带权二分 Description 众所周知,贞鱼是一种高智商水生动物.不过他们到了陆地上智商会减半. 这不?他们遇到了大麻烦! n只贞鱼到陆地上乘车,现在有k辆汽 ...
- [WC2018]即时战略(LCT,splay上二分)
[UOJ题面]http://uoj.ac/problem/349 一道非常好的与数据结构有关的交互题. 首先先看部分分做法, 一上来我们肯定得钦定一个 \(explore\) 的顺序,直接随机就好. ...
随机推荐
- mysql用户管理,权限管理
mysql权限 相关操作: 授予的权限分为四组: 列权限:和表中的一个具体列相关,例如:使用update 语句更新test表中name 列的值 表权限:和一个具体的表的所有数据相关,例如:使用 sel ...
- Memcached服务器安装、配置、使用详解
管理memcached服务 启动Memcached 一般情况下,简单地可以使用类似如下形式,启动Memcached服务: /usr/local/bin/memcached -d -m 64 -I 20 ...
- WPF MVVM 用户控件完成分页
项目中经常会有分页查询的情况,在WPF中我们可以通过用户控件完成分页 一下为分页控件的页面代码, <UserControl x:Class="Foundation.UCtrl.Next ...
- ACE 6.2.0 RHEL6_Linux 编译
第一步. 设置环境变量 export ACE_ROOT=$HOME/ace/ACE_wrappersexport LD_LIBRARY_PATH=$ACE_ROOT/ace:$ACE_ROOT/lib ...
- CRUD生成器DBuilder设计与实现
源码位于github:https://github.com/lvyahui8/dbuilder.git .文中图片如果太小看不清楚,请右键点击“在新标签页中打开”即可看到原图 有兴趣还可以加QQ群交流 ...
- 数据结构与算法C语言实现笔记(1)--表
声明:此一系列博客为阅读<数据结构与算法分析--C语言描述>(Mark Allen Weiss)笔记,部分内容参考自网络:转载请注明出处. 1.表 表是最简单的数据结构,是形如A1.A2. ...
- 2016032701 - ubuntu安装jdk
参考地址:http://jingyan.baidu.com/article/d621e8da0e92052865913f32.html 1.首先需要去oracle官网去下载jdk1.8,我本人下载的是 ...
- CODEVS 1004四子连棋
[题目描述 Description] 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑 ...
- Java练习题
1.实现一个类似于ConcurrentHashMap的分段加锁 import java.util.HashMap; import java.util.Map; import java.util.con ...
- javascript和jquery动态创建html元素
1.javascript创建元素 创建select var select = document.createElement("select"); elect.opti ...