bzoj 1014 LCP 二分 Hash 匹配
求同一字符串的两个后缀的最长公共前缀。
将字符串按位置放到Splay中维护(每个节点还维护一下该子树的hash),然后二分前缀的长度,用splay计算出指定范围的hash,按hash是否相等来判断是否相同。
1 /************************************************************** 2 Problem: 1014 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:7188 ms 7 Memory:4900 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <iostream> 12 #include <cstring> 13 #define maxn 100030 14 using namespace std; 15 16 typedef unsigned long long ulng; 17 18 struct Splay { 19 int pre[maxn], son[maxn][2], ch[maxn], siz[maxn], ntot, root; 20 ulng hash[maxn]; 21 ulng power[maxn]; 22 23 int newnode( int p, int c ) { 24 int nd = ++ntot; 25 pre[nd] = p; 26 son[nd][0] = son[nd][1] = 0; 27 ch[nd] = c; 28 siz[nd] = 1; 29 hash[nd] = c; 30 return nd; 31 } 32 void update( int nd ) { 33 int ls = son[nd][0], rs = son[nd][1]; 34 siz[nd] = siz[ls]+siz[rs]+1; 35 hash[nd] = hash[ls]*power[siz[rs]+1]+ch[nd]*power[siz[rs]]+hash[rs]; 36 } 37 int build( int p, const char *str, int lf, int rg ) { // [lf,rg] 38 if( lf>rg ) return 0; 39 if( lf==rg ) return newnode(p,str[lf]-'a'); 40 int mid = (lf+rg)>>1; 41 int nd = newnode( p, str[mid]-'a' ); 42 son[nd][0] = build( nd, str, lf, mid-1 ); 43 son[nd][1] = build( nd, str, mid+1, rg ); 44 update( nd ); 45 return nd; 46 } 47 void init( const char *str ) { 48 root = ntot = 0; 49 power[0] = 1ULL; 50 for( int i=1; i<maxn; i++ ) 51 power[i] = power[i-1]*27ULL; 52 53 root = newnode( 0, 'a'-'a' ); 54 int rnd = son[root][1] = newnode( root, 'a'-'a' ); 55 son[rnd][0] = build( rnd, str, 0, strlen(str)-1 ); 56 update( rnd ); 57 update( root ); 58 } 59 void rotate( int nd, int d ) { 60 int p = pre[nd]; 61 int s = son[nd][!d]; 62 int ss = son[s][d]; 63 64 son[nd][!d] = ss; 65 son[s][d] = nd; 66 if( p ) son[p][ nd==son[p][1] ] = s; 67 else root = s; 68 69 pre[s] = p; 70 pre[nd] = s; 71 if( ss ) pre[ss] = nd; 72 73 update( nd ); 74 update( s ); 75 } 76 void splay( int nd, int top=0 ) { 77 while( pre[nd]!=top ) { 78 int p = pre[nd]; 79 int nl = nd==son[p][0]; 80 if( pre[p]==top ) { 81 rotate( p, nl ); 82 } else { 83 int pp = pre[p]; 84 int pl = p==son[pp][0]; 85 if( nl==pl ) { 86 rotate( pp, pl ); 87 rotate( p, nl ); 88 } else { 89 rotate( p, nl ); 90 rotate( pp, pl ); 91 } 92 } 93 } 94 } 95 int find( int pos ) { 96 int nd = root; 97 while(1) { 98 int ls = siz[son[nd][0]]; 99 if( nd==0 ) while(1); 100 101 if( pos<=ls ) { 102 nd = son[nd][0]; 103 } else if( pos>=ls+2 ) { 104 nd = son[nd][1]; 105 pos -= ls+1; 106 } else return nd; 107 } 108 } 109 void add_ch( int pos, int c ) { 110 int lnd = find(pos); 111 int rnd = find(pos+1); 112 splay(lnd); 113 splay(rnd,lnd); 114 son[rnd][0] = newnode( rnd, c ); 115 splay( son[rnd][0] ); 116 } 117 void chg_ch( int pos, int c ) { 118 int nd = find(pos); 119 ch[nd] = c; 120 update( nd ); 121 splay( nd ); 122 } 123 ulng qu_hash( int lf, int rg ) { 124 int lnd = find(lf-1); 125 int rnd = find(rg+1); 126 splay( lnd ); 127 splay( rnd, lnd ); 128 return hash[son[rnd][0]]; 129 } 130 inline int size() { return siz[root]-2; } 131 }; 132 133 Splay T; 134 char str[maxn]; 135 int m; 136 137 int main() { 138 scanf( "%s", str ); 139 T.init(str); 140 scanf( "%d", &m ); 141 while(m--) { 142 char ch[10]; 143 int pos, sa, sb; 144 scanf( "%s", ch ); 145 if( ch[0]=='I' ) { 146 scanf( "%d%s", &pos, ch ); 147 pos++; 148 T.add_ch( pos, ch[0]-'a' ); 149 } else if( ch[0]=='R' ) { 150 scanf( "%d%s", &pos, ch ); 151 pos++; 152 T.chg_ch( pos, ch[0]-'a' ); 153 } else { 154 scanf( "%d%d", &sa, &sb ); 155 sa++, sb++; 156 if( T.qu_hash(sa,sa) != T.qu_hash(sb,sb) ) { 157 printf( "0\n" ); 158 continue; 159 } 160 int len = T.size() - max(sa-1,sb-1) + 1; 161 int rl = 1, rr = len; 162 while( rl<rr ) { 163 int md = (rl+rr+1)>>1; 164 ulng ha = T.qu_hash( sa, sa+md-1 ); 165 ulng hb = T.qu_hash( sb, sb+md-1 ); 166 if( ha==hb ) rl = md; 167 else rr = md-1; 168 } 169 printf( "%d\n", rl ); 170 } 171 } 172 } 173 174