Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix
这是一道用splay/非旋treap做的题(这里用的是非旋treap)
1/2/3是splay/非旋treap的常规操作。对于操作4,可以用哈希法求LCP。记hash(i,L)为子串[i,i+L-1](即第i个开始的L个)的hash值。记s[i]为序列第i位(编号从1开始),n为序列长度
如果通过某种方式做到能在O(logn)时间内取出一段子串的hash值,那么二分答案(即LCP长度x),可以在O(logn)时间内判一个x是否合法(如果hash(l,x)==hash(r,x)则认为[l,l+x-1]和[r,r+x-1]是相同的,合法,否则不合法),可以做到在O(log^2n)内完成一个操作4。当然,hash判字符串是否相同正确性可能受影响,因此可以多计算一些hash,当他们都相同时才认为字符串相同,可以将错误率降到足够小。
如何维护一段子串的hash值?首先定义x为任意整数,定义$hash(i,L)=s[i+L-1]*x^{L-1}+s[i+L-2]*x^{L-2}+...+s[i+1]*x+s[i]$
(这里及之后都省略了取模)
(简单记法:左边乘的次数小)
(另一种记法:另一种求法的伪代码表示:ans=0;for(j=i+L-1;j>=i;j--) ans=ans*x+s[j];)
可以发现:如果已知hash(i,p)和hash(i+p,q)(即已知[i,i+p-1]和[i+p,i+p+q-1]的hash值),要求hash(i,p+q)(就是这两段合起来的hash值),那么:
令j=i+p,那么$hash(i,p+q)$
$=s[j+q-1]*x^{p+q-1}+s[j+q-2]*x^{p+q-2}+...+s[j]*x^p+s[i+p-1]*x^{p-1}+...+s[i]*x^0$
所以$hash(i,p+q)=hash(j,q)*x^p+hash(i,p)=hash(i,p)+hash(i+p,q)*x^p$
这样就得到了对于平衡树某个节点,根据子节点为根的子树的hash值与自身值求以自身为根的子树的hash值的方法(先将左子树和自身合起来,再将结果与右子树合起来)
当然,由于此题有一个翻转操作,对于一个节点要维护两个hash:正向序列hash和反向序列hash。翻转操作时顺便交换一下两个的值。
附:这道题没有卡hash,单hash就能过,
附:听说操作4有O(logn)的方法?待解决
错误记录:
1.141行误用build函数(build是用的左闭右闭区间),输入了(a+1,a+n+1)。(然而不知道为什么虽然过不了udebug的数据然而把题目A掉了)
2.没注意在字符前还是字符后插入
*3.posib函数写错:没有考虑要计算hash值的串超出长度范围的情况(就是第二个"&&"之前的部分)。错了不止一次
4.可能出现的错误:如果hash不用ull自然溢出,自己取模,那么要考虑爆int、爆longlong、负数等等
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 inline int rand1() 5 { 6 static int x=471; 7 return x=(48271LL*x+1)%2147483647; 8 } 9 unsigned long long powx[400010]; 10 struct Node 11 { 12 Node(){} 13 Node* ch[2]; 14 int r; 15 bool flip; 16 int v; 17 unsigned long long h,rh; 18 int size; 19 void upd() 20 { 21 if(ch[0]) ch[0]->pd(); 22 if(ch[1]) ch[1]->pd(); 23 size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0); 24 h=(ch[0]?ch[0]->h:0)+v*powx[ch[0]?ch[0]->size:0]+(ch[1]?ch[1]->h:0)*powx[(ch[0]?ch[0]->size:0)+1]; 25 rh=(ch[1]?ch[1]->rh:0)+v*powx[ch[1]?ch[1]->size:0]+(ch[0]?ch[0]->rh:0)*powx[(ch[1]?ch[1]->size:0)+1]; 26 } 27 void pd() 28 { 29 if(flip) 30 { 31 swap(ch[0],ch[1]); 32 swap(h,rh); 33 if(ch[0]) (ch[0]->flip)^=1; 34 if(ch[1]) (ch[1]->flip)^=1; 35 flip=0; 36 } 37 } 38 }nodes[400010]; 39 Node* root;int mem; 40 Node* getnode(){return nodes+(mem++);} 41 Node* merge(Node* a,Node* b) 42 { 43 if(a==NULL) return b; 44 if(b==NULL) return a; 45 if(a->r < b->r) 46 { 47 a->pd();a->ch[1]=merge(a->ch[1],b);a->upd(); 48 return a; 49 } 50 else 51 { 52 b->pd();b->ch[0]=merge(a,b->ch[0]);b->upd(); 53 return b; 54 } 55 } 56 typedef pair<Node*,Node*> P; 57 P split(Node* a,int n) 58 { 59 if(a==NULL) return P(NULL,NULL); 60 P y; 61 a->pd();int s=a->ch[0] ? a->ch[0]->size : 0; 62 if(s>=n) 63 { 64 y=split(a->ch[0],n); 65 a->ch[0]=y.second;a->upd(); 66 y.second=a; 67 } 68 else 69 { 70 y=split(a->ch[1],n-s-1); 71 a->ch[1]=y.first;a->upd(); 72 y.first=a; 73 } 74 return y; 75 } 76 inline void insert(int k,int x) 77 { 78 Node* t=getnode(); 79 t->ch[0]=t->ch[1]=NULL;t->r=rand1();t->v=x;t->flip=0;t->upd(); 80 P y=split(root,k-1); 81 root=merge(merge(y.first,t),y.second); 82 } 83 inline void erase(int k) 84 { 85 P y=split(root,k-1); 86 P y2=split(y.second,1); 87 root=merge(y.first,y2.second); 88 } 89 inline void reverse(int l,int r) 90 { 91 if(l>r) swap(l,r); 92 P y=split(root,l-1); 93 P y2=split(y.second,r-l+1); 94 y2.first->flip^=1; 95 root=merge(merge(y.first,y2.first),y2.second); 96 } 97 inline int size() 98 { 99 return root ? root->size : 0; 100 } 101 inline unsigned long long geth(int l,int r) 102 { 103 if(l>r) return 0; 104 P y=split(root,l-1); 105 P y2=split(y.second,r-l+1); 106 unsigned long long ans=y2.first ? y2.first->h : 0; 107 root=merge(merge(y.first,y2.first),y2.second); 108 return ans; 109 } 110 Node* build(int *l,int *r) 111 { 112 if(l>r) return NULL; 113 if(l==r) 114 { 115 Node* t=getnode(); 116 t->ch[0]=t->ch[1]=NULL;t->r=rand1();t->v=*l;t->flip=0;t->upd(); 117 return t; 118 } 119 else 120 { 121 int* mid=l+(r-l)/2; 122 return merge(build(l,mid),build(mid+1,r)); 123 } 124 } 125 int n,m,q; 126 int a[200010]; 127 const int X=127; 128 int l,r; 129 inline bool posib(int x) 130 { 131 return (l+x-1<=size())&&(r+x-1<=size())&&(geth(l,l+x-1)==geth(r,r+x-1)); 132 } 133 int main() 134 { 135 register int i; 136 int lx,rx,k,x,mid,tmp; 137 powx[0]=1; 138 for(i=1;i<=400000;i++) powx[i]=powx[i-1]*X; 139 scanf("%d%d",&n,&q); 140 for(i=1;i<=n;i++) scanf("%1d",&a[i]); 141 root=build(a+1,a+n); 142 while(q--) 143 { 144 scanf("%d",&tmp); 145 if(tmp==1) 146 { 147 scanf("%d%d",&k,&x); 148 insert(k+1,x); 149 } 150 else if(tmp==2) 151 { 152 scanf("%d",&k); 153 erase(k); 154 } 155 else if(tmp==3) 156 { 157 scanf("%d%d",&l,&r); 158 reverse(l,r); 159 } 160 else if(tmp==4) 161 { 162 scanf("%d%d",&l,&r); 163 lx=0;rx=size()+1; 164 while(rx-lx>1) 165 { 166 mid=(lx+rx)>>1; 167 if(posib(mid)) lx=mid; 168 else rx=mid; 169 } 170 printf("%d\n",lx); 171 } 172 } 173 return 0; 174 }
https://www.lydsy.com/JudgeOnline/problem.php?id=1014
https://www.luogu.org/problemnew/show/P4036
贴一下常数超大的代码
做法类似
1 #pragma GCC optimize("Ofast") 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 inline int rand1() 7 { 8 static int x=471; 9 return x=(48271LL*x+1)%2147483647; 10 } 11 unsigned long long powx[100010]; 12 struct Node 13 { 14 Node(){} 15 Node* ch[2]; 16 int r; 17 int v; 18 unsigned long long h; 19 int size; 20 void upd() 21 { 22 size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0); 23 h=(ch[0]?ch[0]->h:0)+v*powx[ch[0]?ch[0]->size:0]+(ch[1]?ch[1]->h:0)*powx[(ch[0]?ch[0]->size:0)+1]; 24 } 25 }nodes[250010]; 26 Node* root;int mem; 27 Node* getnode(){return nodes+(mem++);} 28 Node* merge(Node* a,Node* b) 29 { 30 if(a==NULL) return b; 31 if(b==NULL) return a; 32 if(a->r < b->r) 33 { 34 a->ch[1]=merge(a->ch[1],b);a->upd(); 35 return a; 36 } 37 else 38 { 39 b->ch[0]=merge(a,b->ch[0]);b->upd(); 40 return b; 41 } 42 } 43 typedef pair<Node*,Node*> P; 44 P split(Node* a,int n) 45 { 46 if(a==NULL) return P(NULL,NULL); 47 P y; 48 int s=a->ch[0] ? a->ch[0]->size : 0; 49 if(s>=n) 50 { 51 y=split(a->ch[0],n); 52 a->ch[0]=y.second;a->upd(); 53 y.second=a; 54 } 55 else 56 { 57 y=split(a->ch[1],n-s-1); 58 a->ch[1]=y.first;a->upd(); 59 y.first=a; 60 } 61 return y; 62 } 63 inline void insert(int k,int x) 64 { 65 Node* t=getnode(); 66 t->r=rand1();t->v=x;t->upd(); 67 P y=split(root,k-1); 68 root=merge(merge(y.first,t),y.second); 69 } 70 inline void erase(int k) 71 { 72 P y=split(root,k-1); 73 P y2=split(y.second,1); 74 root=merge(y.first,y2.second); 75 } 76 77 inline int size() 78 { 79 return root ? root->size : 0; 80 } 81 inline unsigned long long geth(int l,int r) 82 { 83 if(l>r) return 0; 84 P y=split(root,l-1); 85 P y2=split(y.second,r-l+1); 86 unsigned long long ans=y2.first ? y2.first->h : 0; 87 root=merge(merge(y.first,y2.first),y2.second); 88 return ans; 89 } 90 Node* build(char *l,char *r) 91 { 92 if(l>r) return NULL; 93 if(l==r) 94 { 95 Node* t=getnode(); 96 t->r=rand1();t->v=(int)(*l);t->upd(); 97 return t; 98 } 99 else 100 { 101 char* mid=l+(r-l)/2; 102 return merge(build(l,mid),build(mid+1,r)); 103 } 104 } 105 int n,m,q; 106 char a[100010]; 107 const int X=127; 108 int l,r; 109 char tmp; 110 inline bool posib(int x) 111 { 112 return (l+x-1<=size())&&(r+x-1<=size())&&(geth(l,l+x-1)==geth(r,r+x-1)); 113 } 114 int main() 115 { 116 register int i; 117 int lx,rx,k,mid; 118 powx[0]=1; 119 for(i=1;i<=100000;i++) powx[i]=powx[i-1]*X; 120 scanf("%s",a+1);n=strlen(a+1); 121 root=build(a+1,a+n); 122 scanf("%d",&q); 123 while(q--) 124 { 125 tmp=getchar();while(tmp<'A'||tmp>'Z') tmp=getchar(); 126 if(tmp=='I') 127 { 128 scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar(); 129 insert(k+1,(int)tmp); 130 } 131 else if(tmp=='R') 132 { 133 scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar(); 134 erase(k);insert(k,(int)tmp); 135 } 136 else if(tmp=='Q') 137 { 138 scanf("%d%d",&l,&r); 139 lx=0;rx=size()+1; 140 while(rx-lx>1) 141 { 142 mid=(lx+rx)>>1; 143 if(posib(mid)) lx=mid; 144 else rx=mid; 145 } 146 printf("%d\n",lx); 147 } 148 } 149 return 0; 150 }