描述


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. [.Net MVC] 使用 log4net 日志框架

    项目:后台管理平台 意义:项目开发中提出增加日志功能,对关键的操作.程序运行中的错误信息进行记录,这对程序部署后的调试有很大意义. 注:本文只是对网上搜集的信息进行了整合,以备今后查询. 关键字:.N ...

  2. Putty + Vim + Color

    Putty + Vim + Color 参考: 1.Using colour schemes with vim and putty 2.Putty的颜色 3.Custom PuTTY Color Th ...

  3. 暑假集训(3)第二弹 -----Jungle Roads(Hdu1301)

    问题梗概:自从上次某个acmer来设计了拉格瑞圣岛的交通路线后,岛上的酋长就相当苦恼,他发现,虽然这些修好的公路便利了岛上的 交通,并且让拉格瑞圣岛的旅游业更加兴旺,甚至他们还收到了一笔不小的国际资金 ...

  4. sgu 110 Dungeon

    这道题是计算几何,这是写的第一道计算几何,主要是难在如何求入射光线的反射光线. 我们可以用入射光线 - 入射光线在法线(交点到圆心的向量)上的投影*2 来计算反射光线,自己画一个图,非常清晰明了. 具 ...

  5. MySQL生产库主从重新同步操作注意事项

    因为一些原因,我们会遇到生产主从库重新同步的时候.重新同步MYSQL主从的时候有有一些注意的地方. 从库还原前一定要记得reset,因为重启mysql并不影响复制进程,如果忘记reset,会导致你一边 ...

  6. Javascript 中 null、NaN和undefined的区别

    1.类型分析: js中的数据类型有undefined,boolean,number,string,object等5种,前4种为原始类型,第5种为引用类型. 代码 var a1; var a2 = tr ...

  7. 我忽略了的DOCTYPE!

    最近不知道是不是因为天气的原因,瞌睡太多了,而且每天晚上都做梦,更奇怪的是每次做梦都能够连着上次没有做完的梦继续做.第二天上班又没有精神,人都快崩溃了!不说了,郁闷! 偶然看到一个问题:Doctype ...

  8. itoa函数的递归实现(二级指针实现)

    问题提出 <C Programming Language>书中在递归这一节预留了两个使用递归实现的函数,其中itoa函数是用来将一个整数转换为一个字符串.书中已有使用循环实现的版本,但是直 ...

  9. 021,lambda 表达式

    021,lambda 表达式  匿名函数: 快速定义单行的最小函数,是从lisp借用来的,可以用在任何需要函数的地方 >>> def ds(x):     return 2*x +  ...

  10. vi/vim正则表达式

    http://www.cnblogs.com/penseur/archive/2011/02/25/1964522.html 毋庸多言,在vim中正则表达式得到了十分广泛的应用. 最常用的 / 和 : ...