标签:style blog http color io os ar for 数据
因为一看到有关子串就主动的联想后缀数组
所有后缀的前缀去重后就是所有子串(好像是废话)
这样就可以得到每个后缀的子串个数。
二分查找到第k个所在的位置。
在二分处理所有可以出现该串的sa区间。
最小就是维护sa数组。
1 //rank从0开始 2 //sa从1开始,因为最后一个字符(最小的)排在第0位 3 //high从2开始,因为表示的是sa[i-1]和sa[i] 4 #include <cstdio> 5 #include <cstring> 6 #include <iostream> 7 #include <algorithm> 8 #define root 1,n,1 9 #define lson l,mid,rt<<1 10 #define rson mid+1,r,rt<<1|1 11 #define M 120010 12 #define INF 10000007 13 using namespace std; 14 typedef long long LL; 15 LL rank[M],sa[M],X[M],Y[M],high[M],init[M]; 16 LL buc[M]; 17 struct SegmentTree{ 18 LL Min[M << 2]; 19 void pushup(LL rt){ 20 Min[rt] = min(Min[rt<<1],Min[rt<<1|1]); 21 } 22 void build(LL l,LL r,LL rt){ 23 if(l == r){ 24 Min[rt] = sa[l]; 25 return; 26 } 27 LL mid = (l + r) >> 1; 28 build(lson); 29 build(rson); 30 pushup(rt); 31 } 32 LL query(LL L,LL R,LL l,LL r,LL rt){ 33 if(L <= l && r <= R){ 34 return Min[rt]; 35 } 36 LL mid = (l + r) >> 1; 37 LL ans = INF; 38 if(L <= mid) ans = min(query(L,R,lson),ans); 39 if(mid + 1 <= R) ans = min(query(L,R,rson),ans); 40 return ans; 41 } 42 }; 43 SegmentTree sgt; 44 void calhigh(LL n) { 45 LL i , j , k = 0; 46 for(i = 1 ; i <= n ; i++) rank[sa[i]] = i; 47 for(i = 0 ; i < n ; high[rank[i++]] = k) 48 for(k?k--:0 , j = sa[rank[i]-1] ; init[i+k] == init[j+k] ; k++); 49 } 50 bool cmp(LL *r,LL a,LL b,LL l) { 51 return (r[a] == r[b] && r[a+l] == r[b+l]); 52 } 53 void suffix(LL n,LL m = 128) { 54 LL i , l , p , *x = X , *y = Y; 55 for(i = 0 ; i < m ; i ++) buc[i] = 0; 56 for(i = 0 ; i < n ; i ++) buc[ x[i] = init[i] ] ++; 57 for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; 58 for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[i] ]] = i; 59 for(l = 1,p = 1 ; p < n ; m = p , l *= 2) { 60 p = 0; 61 for(i = n-l ; i < n ; i ++) y[p++] = i; 62 for(i = 0 ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l; 63 for(i = 0 ; i < m ; i ++) buc[i] = 0; 64 for(i = 0 ; i < n ; i ++) buc[ x[y[i]] ] ++; 65 for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; 66 for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[y[i]] ] ] = y[i]; 67 for(swap(x,y) , x[sa[0]] = 0 , i = 1 , p = 1 ; i < n ; i ++) 68 x[ sa[i] ] = cmp(y,sa[i-1],sa[i],l) ? p-1 : p++; 69 } 70 calhigh(n-1);//后缀数组关键是求出high,所以求sa的时候顺便把rank和high求出来 71 } 72 73 74 //当需要反复询问两个后缀的最长公共前缀时用到RMQ 75 LL Log[M]; 76 LL best[20][M]; 77 void initRMQ(LL n) {//初始化RMQ 78 for(LL i = 1; i <= n ; i ++) best[0][i] = high[i]; 79 for(LL i = 1; i <= Log[n] ; i ++) { 80 LL limit = n - (1<<i) + 1; 81 for(LL j = 1; j <= limit ; j ++) { 82 best[i][j] = min(best[i-1][j] , best[i-1][j+(1<<i>>1)]); 83 } 84 } 85 } 86 LL lcp(LL a,LL b) {//询问a,b后缀的最长公共前缀 87 //a = rank[a]; b = rank[b]; 88 //if(a > b) swap(a,b); 89 //a ++; 90 if(a>b)return 0; 91 LL t = Log[b - a + 1]; 92 return min(best[t][a] , best[t][b - (1<<t) + 1]); 93 } 94 95 char str[M]; 96 LL dlen[M]; 97 98 void getlen(LL n,LL len){ 99 //dlen[1]=len-sa[1]; 100 for(LL i=1;i<=n;i++){ 101 dlen[i]=len-sa[i]-high[i]; 102 //printf("%d ",dlen[i]); 103 } 104 //cout<<endl; 105 for(LL i=1;i<=n;i++){ 106 dlen[i]+=dlen[i-1]; 107 } 108 } 109 void findK(LL n,LL k,LL &start,LL &len){ 110 //printf("%I64d %I64d\n",k,dlen[n]); 111 if(k>dlen[n]||k<=0){ 112 start=len=0; 113 return ; 114 } 115 LL l=1,r=n; 116 while(l<=r){ 117 LL mid=(l+r)>>1; 118 if(dlen[mid]>=k) r=mid-1; 119 else l=mid+1; 120 } 121 start=l; 122 len=k-dlen[start-1]+high[start]; 123 //printf("start:%I64d len:%I64d\n",start,len); 124 } 125 LL findLcp(LL start,LL len,LL n){ 126 LL l=start + 1,r=n; 127 while(l<=r){ 128 LL mid=(l+r)>>1; 129 if(lcp(start+1,mid)>=len)l=mid+1; 130 else r=mid-1; 131 } 132 //printf("start:%I64d r:%I64d\n",start,r); 133 return sgt.query(start,r,root); 134 } 135 int main() { 136 //预处理每个数字的Log值,常数优化,用于RMQ 137 LL l,r,q; 138 LL v,u; 139 LL start,llen; 140 Log[0] = -1; 141 for(LL i = 1; i < M ; i ++) { 142 Log[i] = (i&(i-1)) ? Log[i-1] : Log[i-1] + 1 ; 143 } 144 //******************************************* 145 // n为数组长度,下标0开始 146 // 将初始数据,保存在init里,并且保证每个数字都比0大 147 // m = max{ init[i] } + 1 148 // 一般情况下大多是字符操作,所以128足够了 149 //******************************************* 150 151 while(scanf("%s",str)!=EOF){ 152 l = r = 0; 153 LL n=strlen(str); 154 for(LL i=0;i<n;i++)init[i]=str[i]; 155 init[n]=0; 156 suffix(n+1); 157 initRMQ(n); 158 getlen(n,n); 159 sgt.build(root); 160 scanf("%I64d",&q); 161 for(LL i=1;i<=q;i++){ 162 scanf("%I64d",&v); 163 u=(l^r^v)+1; 164 findK(n,u,start,llen); 165 //printf("u:%I64d\n",u); 166 if(llen==0&&start==0){ 167 l=0,r=0; 168 printf("0 0\n"); 169 continue; 170 } 171 LL ans=findLcp(start,llen,n); 172 l=ans;r=ans+llen-1; 173 l++;r++; 174 printf("%I64d %I64d\n",l,r); 175 } 176 } 177 // init[n] = 0; 178 // suffix(n+1,m); 179 } 180 /* 181 acab 182 10 183 2 184 */
标签:style blog http color io os ar for 数据
原文地址:http://www.cnblogs.com/youyouyou/p/3972623.html