码迷,mamicode.com
首页 > Web开发 > 详细

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

时间:2016-06-20 23:58:19      阅读:515      评论:0      收藏:0      [点我收藏+]

标签:

描述


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+二分)

标签:

原文地址:http://www.cnblogs.com/Sunnie69/p/5602162.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!