bzoj 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)
Posted 瓜皮大哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)相关的知识,希望对你有一定的参考价值。
题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度
乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾)
看题解才知道这是一道splay题,首先要对splay维护区间信息有一定了解
splay维护,插入字符,替换字符
而它的字树内所有儿子的中序遍历的hash值也可以通过splay维护
(这个推导式似乎烂大街了)
而后缀就是把i-1拎到根节点,然后把n+1拎到根节点的右儿子上,它的左儿子表示的就是hash值
至于如何查公共前缀呢?二分答案啊!询问的总时间是
这个二分答案的check函数 的满足条件并非常规的>=或者<=,而是==,所以为了防止正确答案被略掉,每次二分的过程中都记录一次mid作为答案,而加下来mid在查询范围内已经没有意义了,所以是r=mid-1而不是r=mid
我一开始插入打错了竟然还有80分,数据太水了hhhhh
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define il inline 5 #define ui unsigned int 6 #define ull unsigned long long 7 #define seed 13131 8 #define N 110000 9 #define root d[0].ch[1] 10 using namespace std; 11 12 char str[N],Q[10],q[10]; 13 ull pw[N]; 14 int n,m,tot; 15 struct SPLAY{int fa,ch[2],sz;ull hsh,val;}d[N]; 16 int gc() 17 { 18 int rett=0,fh=1;char p=getchar(); 19 while(p<‘0‘||p>‘9‘){if(p==‘-‘)fh=-1;p=getchar();} 20 while(p>=‘0‘&&p<=‘9‘){rett=(rett<<3)+(rett<<1)+p-‘0‘;p=getchar();} 21 return rett*fh; 22 } 23 il ull idx(char c){return c-‘a‘+1;} 24 il void con(int x,int ff,int p){d[x].fa=ff,d[ff].ch[p]=x;} 25 il int idf(int x){return d[d[x].fa].ch[0]==x?0:1;} 26 il int cre(ull w){tot++;d[tot].val=w,d[tot].sz=1,d[tot].hsh=w;return tot;} 27 il void pushup(int x) 28 { 29 d[x].sz=d[d[x].ch[0]].sz+d[d[x].ch[1]].sz+1; 30 d[x].hsh=d[d[x].ch[0]].hsh*pw[d[d[x].ch[1]].sz+1]+(ull)d[x].val*pw[d[d[x].ch[1]].sz]+d[d[x].ch[1]].hsh; 31 } 32 il void rot(int x) 33 { 34 int y=d[x].fa;int ff=d[y].fa;int px=idf(x);int py=idf(y); 35 con(d[x].ch[px^1],y,px),con(y,x,px^1),con(x,ff,py); 36 pushup(y),pushup(x); 37 } 38 void splay(int x,int to) 39 { 40 to=d[to].fa; 41 while(d[x].fa!=to){ 42 int y=d[x].fa; 43 if(d[y].fa==to) rot(x); 44 else if(idf(x)==idf(y)){rot(y);rot(x);} 45 else{rot(x);rot(x);} 46 } 47 } 48 int build(int l,int r,int ff) 49 { 50 if(l>r) return 0; 51 int mid=(l+r)>>1; 52 int pos=cre(idx(str[mid])); 53 d[pos].fa=ff; 54 d[pos].ch[0]=build(l,mid-1,pos); 55 d[pos].ch[1]=build(mid+1,r,pos); 56 pushup(pos); 57 return pos; 58 } 59 int find_pos(int pos) 60 { 61 int x=root; 62 while(x) 63 { 64 if(d[d[x].ch[0]].sz>=pos) x=d[x].ch[0]; 65 else{ 66 pos-=d[d[x].ch[0]].sz; 67 if(pos==1) return x; 68 pos--,x=d[x].ch[1]; 69 } 70 } 71 return x; 72 } 73 void ins(int pos,ull w) 74 { 75 int ff=find_pos(pos+1),x,y;splay(ff,root); 76 if(!d[ff].ch[1]) 77 x=cre(w),con(x,ff,1),pushup(ff); 78 else{ 79 x=d[ff].ch[1]; 80 while(x) 81 if(d[x].ch[0]) x=d[x].ch[0]; 82 else break; 83 y=cre(w),con(y,x,0),pushup(x); 84 splay(x,root); 85 } 86 } 87 void replac(int pos,ull w) 88 { 89 int x=find_pos(pos+1);splay(x,root); 90 d[x].val=w;pushup(x); 91 } 92 il ull get_hsh(int pos) 93 { 94 int x=find_pos(pos); 95 splay(x,root); 96 int y=find_pos(n+2); 97 splay(y,d[x].ch[1]); 98 return d[d[d[x].ch[1]].ch[0]].hsh; 99 } 100 il int check(int x,int y,int mid) 101 { 102 ull s1=0,s2=0,s3=0,s4=0; 103 s1=get_hsh(x); 104 if(x+mid<=n) s2=get_hsh(x+mid); 105 s3=get_hsh(y); 106 if(y+mid<=n) s4=get_hsh(y+mid); 107 return (s1-s2==(s3-s4)*pw[y-x])?1:0; 108 } 109 int Query(int a,int b) 110 { 111 if(a>b){int t=a;a=b;b=t;} 112 int l=1,r=n-b+1,ans=0; 113 while(l<=r){ 114 int mid=(l+r)>>1; 115 if(check(a,b,mid)) ans=mid,l=mid+1; 116 else r=mid-1; 117 } 118 return ans; 119 } 120 void stt() 121 { 122 n=strlen(str+1);pw[0]=1; 123 for(int i=1;i<=100000;i++) pw[i]=pw[i-1]*seed; 124 int x=cre(0),y=cre(0),z; 125 con(x,0,1),con(y,1,1); 126 z=build(1,n,y); 127 con(z,y,0); 128 pushup(y),pushup(x); 129 } 130 131 int main() 132 { 133 scanf("%s",str+1); 134 stt(); 135 scanf("%d",&m); 136 int x,y; 137 for(int i=1;i<=m;i++) 138 { 139 scanf("%s",Q); 140 if(Q[0]==‘Q‘){ 141 x=gc(),y=gc(); 142 printf("%d ",Query(x,y)); 143 }else if(Q[0]==‘I‘){ 144 x=gc();scanf("%s",q); 145 ins(x,idx(q[0])); 146 n++; 147 }else{ 148 x=gc();scanf("%s",q); 149 replac(x,idx(q[0])); 150 } 151 } 152 return 0; 153 }
以上是关于bzoj 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
[BZOJ]1014 火星人prefix(JSOI2008)