BZOJ_1014_[JSOI2008]_火星人prefix_(Splay+LCP_Hash+二分)

Posted 晴歌。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.调了好久发现是字符串读入的问题...(拍脸)

 

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=1e5+5;
 5 typedef unsigned long long ull;
 6 int n,m;
 7 ull p[maxn];
 8 char s[maxn];
 9 struct Splay{
10     struct node{
11         node* c[2],* f;
12         int v,s; ull h;
13         node(int v,node* t):v(v){ s=1;h=v;f=c[0]=c[1]=t; }
14         bool d(){ return f->c[1]==this; }
15         void setc(node* x,bool d){ c[d]=x; x->f=this; }
16         void push_up(){
17             s=c[0]->s+c[1]->s+1;
18             h=c[0]->h+(ull)v*p[c[0]->s]+c[1]->h*p[c[0]->s+1];
19         }
20     }* root,* null;
21     Splay(){
22         null=new node(0,0);null->s=0;
23         root=new node(0,null); root->setc(new node(0,null),1);
24     }
25     void rot(node* x){
26         node* f=x->f; bool d=x->d();
27         f->f->setc(x,f->d());
28         f->setc(x->c[!d],d);
29         x->setc(f,!d);
30         f->push_up();
31         if(f==root) root=x;
32     }
33     void splay(node* x,node *f){
34         while(x->f!=f)
35             if(x->f->f==f) rot(x);
36             else x->d()==x->f->d()?(rot(x->f),rot(x)):(rot(x),rot(x));
37         x->push_up();
38     }
39     node* kth(int k){
40         for(node* t=root;t!=null;){
41             int s=t->c[0]->s;
42             if(k==s) return t;
43             if(k>s) t=t->c[1], k-=s+1;
44             else t=t->c[0];
45         }
46     }
47     node* get_range(int l,int r){
48         splay(kth(l-1),null);
49         splay(kth(r+1),root);
50         return root->c[1]->c[0];
51     }
52     void ins(int v,int pos){
53         node *f=get_range(pos,pos);
54         f->setc(new node(v,null),1); splay(f->c[1],null);
55     }
56     void chg(int v,int pos){
57         node *x=get_range(pos,pos);
58         x->v=v; splay(x,null);
59     }
60     int hash(int l,int r){ return get_range(l,r)->h; }
61     node* build(int l,int r){
62         if(l>r) return null;
63         int m=l+(r-l)/2;
64         node *t=new node(s[m]-\'a\'+1,null);
65         t->setc(build(l,m-1),0);
66         t->setc(build(m+1,r),1);
67         t->push_up();
68         return t;
69     }
70 }T;
71 inline int read(int &x){ x=0;int k=1;char c;for(c=getchar();c<\'0\'||c>\'9\';c=getchar())if(c==\'-\')k=-1;for(;c>=\'0\'&&c<=\'9\';c=getchar())x=x*10+c-\'0\';return x*=k; }
72 inline char read(char &c){ for(c=getchar();(c<\'a\'||c>\'z\')&&(c<\'A\'||c>\'Z\');c=getchar());return c; }
73 int bsearch(int x,int y){
74     int s=T.root->s-2;
75     int l=0,r=min(s-x,s-y)+1,mid;
76     while(l<r){
77         mid=l+(r-l+1)/2;
78         if(T.hash(x,x+mid-1)==T.hash(y,y+mid-1)) l=mid;
79         else r=mid-1;
80     }
81     return l;
82 }
83 void init(){
84     scanf("%s",s+1); n=strlen(s+1); read(m);
85     p[0]=1;
86     for(int i=1;i<maxn;i++) p[i]=p[i-1]*(ull)27;
87     T.root->c[1]->setc(T.build(1,n),0); T.root->c[1]->push_up(); T.root->push_up();
88 }
89 int main(){
90     init();
91     while(m--){
92         char c; int x,y;
93         read(c); read(x);
94         if(c==\'Q\'){ read(y); printf("%d\\n",bsearch(x,y)); }
95         else if(c==\'R\') T.chg(read(c)-\'a\'+1,x);
96         else T.ins(read(c)-\'a\'+1,x);
97     }
98     return 0;
99 }
View Code

 

以上是关于BZOJ_1014_[JSOI2008]_火星人prefix_(Splay+LCP_Hash+二分)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1014[JSOI2008]火星人prefix

bzoj1014: [JSOI2008]火星人prefix

[BZOJ1014][JSOI2008]火星人prefix

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

[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash

[BZOJ]1014 火星人prefix(JSOI2008)