bzoj 1014 [JSOI2008]火星人prefix(splay+hash)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1014 [JSOI2008]火星人prefix(splay+hash)相关的知识,希望对你有一定的参考价值。
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1014
【题意】
给定一个字符串,要求提供修改一个字符,插入一个字符,查询两个后缀LCP的功能。
【思路】
splay维护字符串的哈希值。因为要提供区间,splay采用先查找后调整至根的写法。
一个结点的hash值为:
ch[0]->h * X^(ch[1]->s+1)+v * X^(ch[1]->s)+ch[1]->h
对于一个询问每次二分长度,提取区间后比较hash值即可。
需要注意的是splay要提前在区间的左右两边各加上一个节点,不然会调用到null。
ull自然溢出相当于模2^64。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 typedef unsigned long long ull; 15 const int N = 5e5+10; 16 const int X = 27; 17 18 ll read() { 19 char c=getchar(); 20 ll f=1,x=0; 21 while(!isdigit(c)) { 22 if(c==‘-‘) f=-1; c=getchar(); 23 } 24 while(isdigit(c)) 25 x=x*10+c-‘0‘,c=getchar(); 26 return x*f; 27 } 28 29 char s[N]; 30 int n,q; 31 ull powx[N]; 32 33 struct Node* null; 34 struct Node { 35 int s,v; ull h; 36 Node* ch[2]; 37 int cmp(int k) { 38 if(k==ch[0]->s+1) return -1; 39 return k<=ch[0]->s? 0:1; 40 } 41 void init(int x) { 42 v=h=x; s=1; 43 ch[0]=ch[1]=null; 44 } 45 void maintain() { 46 s=ch[0]->s+ch[1]->s+1; 47 h=ch[0]->h*powx[ch[1]->s+1]+v*powx[ch[1]->s]+ch[1]->h; 48 } 49 } *root,nodepool[N]; int nodesz=0; 50 51 void rot(Node* &o,int d) { 52 Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; 53 o->maintain(),k->maintain(); o=k; 54 } 55 void splay(Node*& o,int k) { 56 int d=o->cmp(k); 57 if(d==1) k-=o->ch[0]->s+1; 58 if(d!=-1) { 59 Node* p=o->ch[d]; 60 int d2=p->cmp(k),k2=(d2==0?k:k-p->ch[0]->s-1); 61 if(d2!=-1) { 62 splay(p->ch[d2],k2); 63 if(d==d2) rot(o,d^1); else rot(o->ch[d],d); 64 } 65 rot(o,d^1); 66 } 67 } 68 //return range (l,r] 69 //加过点后 s[l,r]=range(l,r+1) 70 Node*& range(int l,int r) { 71 splay(root,l); 72 splay(root->ch[1],r-l+1); 73 return root->ch[1]->ch[0]; 74 } 75 76 Node* build(int l,int r) 77 { 78 if(r<l) return null; 79 int mid=l+r>>1; 80 Node* o=&nodepool[++nodesz]; 81 o->init(s[mid]-‘a‘+1); 82 o->ch[0]=build(l,mid-1); 83 o->ch[1]=build(mid+1,r); 84 o->maintain(); 85 return o; 86 } 87 void insert(int p,int v) 88 { 89 splay(root,p+1); 90 Node* o=&nodepool[++nodesz]; 91 o->init(v); 92 o->ch[0]=root->ch[0]; o->ch[1]=null; 93 o->maintain(); 94 root->ch[0]=o; root->maintain(); 95 } 96 void change(int p,int v) 97 { 98 splay(root,p); 99 root->v=v; 100 root->maintain(); 101 } 102 103 int main() 104 { 105 //freopen("in.in","r",stdin); 106 //freopen("out.out","w",stdout); 107 null=new Node(); 108 scanf("%s",s+1); 109 int n=strlen(s+1); 110 s[0]=‘z‘+1; s[++n]=‘z‘+1; s[n+1]=‘\0‘; 111 scanf("%d",&q); 112 powx[0]=1; 113 FOR(i,1,n+q) powx[i]=powx[i-1]*X; 114 root=build(0,n); 115 while(q--) { 116 char op[2],val[2]; 117 int x,y; 118 scanf("%s%d",op,&x); 119 if(op[0]==‘R‘) { 120 scanf("%s",val); 121 change(x+1,val[0]-‘a‘+1); 122 } else 123 if(op[0]==‘I‘) { 124 scanf("%s",val); 125 insert(x+1,val[0]-‘a‘+1); 126 } else { 127 scanf("%d",&y); 128 int len=root->s,L=0,R=0; 129 R=min(len-y-1,len-x-1); 130 while(L<R) { 131 int M=L+(R-L+1)/2; 132 ull H=range(x,x+M)->h; 133 H-=range(y,y+M)->h; 134 if(!H) L=M; else R=M-1; 135 } 136 printf("%d\n",L); 137 } 138 139 } 140 return 0; 141 }
以上是关于bzoj 1014 [JSOI2008]火星人prefix(splay+hash)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
[BZOJ]1014 火星人prefix(JSOI2008)