Jewel Magic UVA - 11996 這是一道用splay/非旋treap做的題(這裡用的是非旋treap) 1/2/3是splay/非旋treap的常規操作。對於操作4,可以用哈希法求LCP。記hash(i,L)為子串[i,i+L-1](即第i個開始的L個)的hash值。記s[i]為序列 ...
這是一道用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 }