bzoj 1014: [JSOI2008]火星人prefix
Posted qt666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1014: [JSOI2008]火星人prefix相关的知识,希望对你有一定的参考价值。
Description
火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:madamimadam,
我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,
火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串
,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程
中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,
如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速
算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说
,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此
复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。
Input
第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操
作有3种,如下所示
1、询问。语法:Qxy,x,y均为正整数。功能:计算LCQ(x,y)限制:1<=x,y<=当前字符串长度。
2、修改。语法:Rxd,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字
符串长度。
3、插入:语法:Ixd,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x=0,则在字
符串开头插入。限制:x不超过当前字符串长度
Output
对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。
Sample Input
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11
Sample Output
1
0
2
1
HINT
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
Source
今天终于把这个名为"火星人”的坑给填了。。。
这道题曾经对刚打完营业额统计的我产生了巨大的心理阴影。。。
直到昨天晚自习无聊看刘汝佳白书,陡然发现有一个名叫魔法珠宝的题勾起了我童年的回忆。。。
对于字符串的多次修改,后缀数组是不能胜任的(蒟蒻并不会),看到插入,修改。。splay就能排上用场了。。。
求LCP的话用二分+哈希可以在logn的时间判断,就是二分一个长度用哈希值判断两个串是否相等。。。
不得不说哈希真的是解决字符串问题的万能方法。。。O(1)判断啊,开玩笑。。。。
splay的作用就是用来维护这个字符串的。。。其中每个节点相当与掌握了他所管辖区间的一段的哈希值。。。。
update的时候再由左右儿子的哈希值重新计算,这就需要再维护一个子树大小了。。。(算哈希用)。。。。
就像这样:hsh[x]=hsh[left[x]]+v[x]*pre[size[left]]+hsh[r]*pre[size[left]+1]。。。。。
每次询问相当于是要提取一段的哈希值。。。
对于询问,对于需要的一个子串首先找到子串的首字母,把它伸展到根,然后找到子串的尾字母的下一个字母,把它伸展到根的右儿子,那么根的右儿子的左儿子的哈希值就是答案。
对于插入操作:
把插入位置splay到根,下一位splay到根的右子树,然后直接往根的右子树的左子树上插就可以了,直接在根结点上修改再update()。
修改操作就没什么好说的了。。。直接splay到根,修改再update();
不得不说这个题真的有点码,关键是难调。。。splay天旋地转调个鬼。。。
Orz 这是jesseliu612大佬的splay入门题。。。。
今天长见识了,原来是不能定hash这个数组的。。。CE。。。
貌似跑得贼慢。。。9600ms踩线过
1 // MADE BY QT666 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<iostream> 6 #include<queue> 7 #include<set> 8 #include<cstdlib> 9 #include<cstring> 10 #include<string> 11 #include<ctime> 12 #define lson num<<1 13 #define rson num<<1|1 14 #define int long long 15 using namespace std; 16 typedef long long ll; 17 const int N=150005; 18 const int mod=23333333; 19 int size[N],v[N],hsh[N],pre[N]; 20 int c[N][2],fa[N]; 21 int n,m,rt,sz; 22 char ch[N]; 23 int gi() 24 { 25 int x=0,flag=1; 26 char ch=getchar(); 27 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) flag=-1;ch=getchar();} 28 while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); 29 return x*flag; 30 } 31 inline void update(int x) 32 { 33 int l=c[x][0],r=c[x][1]; 34 size[x]=size[l]+size[r]+1; 35 hsh[x]=hsh[l]+v[x]*pre[size[l]]+pre[size[l]+1]*hsh[r]; 36 } 37 inline void rotate(int x,int &k) 38 { 39 int y=fa[x],z=fa[y],l,r; 40 if(c[y][0]==x)l=0;else l=1;r=l^1; 41 if(y==k) k=x; 42 else{if(c[z][0]==y) c[z][0]=x;else c[z][1]=x;} 43 fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 44 c[y][l]=c[x][r],c[x][r]=y; 45 update(y);update(x); 46 } 47 inline void splay(int x,int &k) 48 { 49 while(x!=k) 50 { 51 int y=fa[x],z=fa[y]; 52 if(y!=k) 53 { 54 if((c[y][0]==x)^(c[z][0]==y)) rotate(x,k); 55 else rotate(y,k); 56 } 57 rotate(x,k); 58 } 59 } 60 inline int find(int x,int y) 61 { 62 int l=c[x][0],r=c[x][1]; 63 if(size[l]+1==y) return x; 64 else if(size[l]>=y) return find(l,y); 65 else return find(r,y-size[l]-1); 66 } 67 inline int query(int k,int len) 68 { 69 int x=find(rt,k),y=find(rt,k+len+1); 70 splay(x,rt);splay(y,c[x][1]); 71 return hsh[c[y][0]]; 72 } 73 inline void insert(int k,int val) 74 { 75 int x=find(rt,k+1),y=find(rt,k+2); 76 splay(x,rt);splay(y,c[x][1]); 77 int z=++sz;c[y][0]=z;fa[z]=y;v[z]=val; 78 update(z);update(y);update(x); 79 } 80 inline int work(int x,int y) 81 { 82 int l=1,r=min(sz-x,sz-y)-1,ans=0; 83 while(l<=r) 84 { 85 int mid=(l+r)>>1; 86 if(query(x,mid)==query(y,mid)) l=mid+1,ans=mid; 87 else r=mid-1; 88 } 89 return ans; 90 } 91 inline void build(int l,int r,int f) 92 { 93 if(l>r)return; 94 int mid=(l+r)>>1; 95 if(l==r) 96 { 97 v[l]=hsh[l]=ch[l]-‘a‘+1;size[l]=1; 98 } 99 else build(l,mid-1,mid),build(mid+1,r,mid); 100 v[mid]=ch[mid]-‘a‘+1;fa[mid]=f;update(mid); 101 if(mid<f)c[f][0]=mid; 102 else c[f][1]=mid; 103 } 104 main() 105 { 106 scanf("%s",ch+2); 107 n=strlen(ch+2); 108 pre[0]=1;for(int i=1;i<=N-1;i++) pre[i]=pre[i-1]*27; 109 build(1,n+2,0);sz=n+2;rt=(n+3)>>1; 110 m=gi(); 111 int x,y; 112 char s[2],d[2]; 113 for(int i=1;i<=m;i++) 114 { 115 scanf("%s",s+1); 116 x=gi(); 117 if(s[1]) 118 { 119 if(s[1]==‘Q‘) y=gi(),printf("%lld\n",work(x,y)); 120 else if(s[1]==‘R‘) 121 { 122 scanf("%s",d+1);x=find(rt,x+1);splay(x,rt); 123 v[rt]=d[1]-‘a‘+1;update(rt); 124 } 125 else if(s[1]==‘I‘) {scanf("%s",d+1);insert(x,d[1]-‘a‘+1);} 126 } 127 } 128 return 0; 129 }
以上是关于bzoj 1014: [JSOI2008]火星人prefix的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
[BZOJ]1014 火星人prefix(JSOI2008)