描述


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+二分)的更多相关文章

  1. 【bzoj1014】[JSOI2008]火星人prefix Splay+Hash+二分

    题目描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 ...

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

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

  3. 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$ ...

  4. bzoj1014: [JSOI2008]火星人prefix splay+hash+二分

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  5. 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解

    题意不赘述了,太清晰了. 说题解:首先依据原字符串建立SPT.首尾建议多加一个空白字符. 给一个树构图,依照平衡树的前后大小顺序性质能够使它们始终维持为一个序列,而且能够通过rank找到序列的第k个. ...

  6. BZOJ_1014_[JSOI2008]火星人prefix_splay+hash

    BZOJ_1014_[JSOI2008]火星人prefix_splay+hash 题意:火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam, 我们 ...

  7. 【BZOJ1014】火星人(Splay,哈希)

    [BZOJ1014]火星人(Splay,哈希) 题面 BZOJ 题解 要动态维护这个串,一脸的平衡树. 那么用\(Splay\)维护这个哈希值就好了. 每次计算答案的时候二分+Splay计算区间哈希值 ...

  8. BZOJ_5311_贞鱼_决策单调性+带权二分

    BZOJ_5311_贞鱼_决策单调性+带权二分 Description 众所周知,贞鱼是一种高智商水生动物.不过他们到了陆地上智商会减半. 这不?他们遇到了大麻烦! n只贞鱼到陆地上乘车,现在有k辆汽 ...

  9. [WC2018]即时战略(LCT,splay上二分)

    [UOJ题面]http://uoj.ac/problem/349 一道非常好的与数据结构有关的交互题. 首先先看部分分做法, 一上来我们肯定得钦定一个 \(explore\) 的顺序,直接随机就好. ...

随机推荐

  1. FreeMarker语法2

    FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主要由如下4个部分组成: 1,文本:直接输出的部分 2,注释:<#-- ... -->格式部分,不会输 ...

  2. ZOJ 3211 Dream City(DP)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3374 题目大意:JAVAMAN 到梦幻城市旅游见到了黄金树,黄金树上 ...

  3. Java7 switch新特性

    在Java7之前,switch只能匹配整数值,和字符:而Java7添加了字符串的匹配特性. 代码如下: package blog; public class Main { public static ...

  4. 九度OJ 1531 货币面值(网易游戏2013年校园招聘笔试题) -- 动态规划

    题目地址:http://ac.jobdu.com/problem.php?pid=1531 题目描述: 小虎是游戏中的一个国王,在他管理的国家中发行了很多不同面额的纸币,用这些纸币进行任意的组合可以在 ...

  5. C++实现一个单例模板类

    单例模式在项目开发中使用得比较多,一个单例的模板类显得很有必要,避免每次都要重复定义一个单例类型 //非多线程模式下的一个单例模板类的实现 // template_singleton.h #inclu ...

  6. JSP九大内置对象和四个作用域

    JSP九大内置对象和四个作用域 在学习JSP的时候,首先就要先了解JSP的内置对象,什么是内置对象呢?内置对象也叫隐含对象,就是不需要预先声明就可以在脚本代码和表达式中随意使用.而这样的内置对象在JS ...

  7. div高度自适应填充剩余部分

    在乐学一百的开发过程中,遇到了一个小乐Fm开发,需要跟百度fm差不多,上边一个条,下边一个条,中间部分填充.但是还不能固定高度,因为屏幕的宽高都不一样...height:100%是不可行的.搜了一圈, ...

  8. phantomjs 自动化测试

    最近网站的质量检查越来越严格,原来开发过程中很多隐蔽的问题,逐渐暴露出来,为提高前端的工作效率,就想到是不是可以在开发过程中能自动的对页面的中一些规范化的东西进行自动监测,这个就可以省去不少麻烦. 整 ...

  9. jQuery(function(){})与(function(){})(jQuery)的区别

    jQuery(function(){ });/$(function(){ });全写为 $(document).ready(function(){}); 意义为在DOM加载完毕后执行了ready()方 ...

  10. MySQL基础学习之开始

    学习MySQL数据库几个月了,从什么都不懂到现在这个地步,说实话感触很大,也感觉自己有许多不足之处.当接触MySQL的时候, 连创建一个数据表都想了很长的时间,不知道许多东西.幸亏我有一个好的老师,她 ...