描述


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. Colored Linux Man pages

    Colored Linux Man pages 一.什么是Linux Man 参考: 二.如何高效率地使用Man 三.给Linux Man命令添加点颜色. 1.Unix / Linux: Displa ...

  2. 第8条:覆盖equals时遵守通用约定

    如果不需要覆盖equals方法,那么就无需担心覆盖equals方法导致的错误. 什么时候不需要覆盖equals方法? 1.类的每个实例本质上是唯一的. 例如对于Thread,Object提供的equa ...

  3. WebClient以POST方式发送Web请求

    本例使用WebClient以POST方式发送Web请求并下载一个文件,难点是postData的构造,发送Web请求时有的网站要求可能要求 Cookies前后一致.其中application/x-www ...

  4. 关于Active控件的电子签名 转

    关于Active控件的电子签名 两种方案:一是自己制作证书,客户端安装证书后就可以识别该控件:二就是买官方的喽,在国内找verisign的代理,负责各种电子签名,任何一台浏览器都可以识别该证书.该公司 ...

  5. 网络设备作用和工作ISO层

    物理层——中继器和集线器 二者都起数字信号放大和中转的作用. 中继器 Repeater 用来延长网络距离的互连设备.REPEATER可以增强线路上衰减的信号,它两端即可以连接相同的传输媒体,也可以连接 ...

  6. 【BZOJ】1051: [HAOI2006]受欢迎的牛

    [HAOI2006]受欢迎的牛 Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢 ...

  7. cocos2d-js Mac下的JSB绑定步骤

    cocos2d-js由于采用js语言,使得做一些native的功能比较受限,例如文件和目录操作.socket操作等.逼不得已,这时我们就不得不做jsbinding了.. 官方提供的jsbinding方 ...

  8. 开发设计模式(七)工厂模式(Factory Method Pattern)

    工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根 ...

  9. Unity3d Shader开发(四)UsePass ,GrabPass ,SubShader Tags

    (一)UsePass 命令 使用 来自另一个着色器的命名通道. Syntax 语法 UsePass "Shader/Name" 插入所有来自给定着色器中的给定名字的通道.Shade ...

  10. 洛谷 P1064 金明的预算方案

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...