hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树
我们考虑,一个子串必定是某个后缀的前缀。
排序相邻的后缀他们的前缀一定最相似。
所以全部的一种子串必定是一些排序相邻的后缀的公共前缀。
从l开始的子串,则从rank[l]开始看,两侧height保证大于子串长度,能延伸多长,则证明有多少个这种子串。
我们用ST表维护出height的最小值,然后通过最小值二分即可,边界有些棘手。
然后我们就得到了一个height不小于子串长度的连续区间,这个区间是以原后缀的字典序排序的。
而同时,sa数组下标为排序,值为原串位置。
所以我们对这个区间在sa数组上做主席树,求第k大,即为第k个子串出现的位置。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 const int MAXN = 101000; 7 char str[MAXN]; 8 int len,q,T,m,uni[30]; 9 struct ktree 10 { 11 int n,cnt; 12 int root[MAXN]; 13 int ls[MAXN * 40],rs[MAXN * 40],s[MAXN * 40]; 14 //插入一个新的版本,参数分别为左右区间,最近的历史版本,现在的版本,插入的值 15 //k值加一个引用可以完美的处理新子节点的序号分配问题。 16 //s数组记录了对应序号子树的元素个数 17 void insert(int l,int r,int pre,int &k,int v) 18 { 19 k = ++cnt; 20 s[k] = s[pre] + 1; 21 if (l == r) 22 return; 23 int mid = (l + r) >> 1; 24 //由于我们k值传了引用参,所以这里可以直接将左右节点全部赋上值。 25 ls[k] = ls[pre]; 26 rs[k] = rs[pre]; 27 //根据情况来进行左右递归。 28 if (v <= mid) 29 insert(l,mid,ls[pre],ls[k],v); 30 else 31 insert(mid + 1,r,rs[pre],rs[k],v); 32 } 33 //查询x,y两个历史版本的权值线段树相减的得到新的线段树中的第k大 34 //这里我们考虑一下,如果我们求区间[x,y]的第k大。那么显然第x-1个版本相当于[1,x-1]的权值线段树,那么我们用第y个版本的线段树-第x-1个版本的线段树,得到就相当于是[x,y]区间得到的权值线段树,然后我们可以在这棵线段树上进行开心的查询。 35 int ask(int l,int r,int k,int x,int y) 36 { 37 if (l == r) 38 return l; 39 int mid = (l + r) >> 1; 40 if (s[ls[y]] - s[ls[x]] >= k) 41 return ask(l,mid,k,ls[x],ls[y]); 42 return ask(mid + 1,r,k - (s[ls[y]] - s[ls[x]]),rs[x],rs[y]); 43 } 44 void build(int _n,int *vec) 45 { 46 n = _n; 47 for (int i = 1; i <= n; i++) 48 insert(1,n,root[i - 1],root[i],vec[i]); 49 } 50 void clear() 51 { 52 for (int i = 1; i <= cnt; i++) 53 s[i] = ls[i] = rs[i] = 0; 54 for (int i = 0; i <= n; i++) 55 root[i] = 0; 56 n = 0; 57 cnt = 0; 58 } 59 } kt; 60 struct suffixvec 61 { 62 int c[MAXN],sa[MAXN],rnk[MAXN],height[MAXN],tp[MAXN]; 63 int m,len; 64 char str[MAXN]; 65 void build(int _len,char *s) 66 { 67 len = _len; 68 strcpy(str + 1,s + 1);//因为要从1开始 69 } 70 void clear() 71 { 72 for (int i = 1; i <= len; i++) 73 sa[i] = rnk[i] = height[i] = 0; 74 } 75 void qsort() 76 { 77 for (int i = 0; i <= m; i++) 78 c[i] = 0; 79 for (int i = 1; i <= len; i++) 80 c[rnk[i]]++; 81 for (int i = 1; i <= m; i++) 82 c[i] += c[i - 1]; 83 for (int i = len; i >= 1; i--) 84 sa[c[rnk[tp[i]]]--] = tp[i]; 85 } 86 void get_sa() 87 { 88 m = 200; 89 for (int i = 1; i <= len; i++) 90 { 91 rnk[i] = str[i]; 92 tp[i] = i; 93 } 94 qsort(); 95 for (int k = 1,p = 0; p < len; m = p,k <<= 1) 96 { 97 p = 0; 98 for (int i = 1; i <= k; i++) 99 tp[++p] = len - k + i; 100 for (int i = 1; i <= len; i++) 101 if (sa[i] > k) 102 tp[++p] = sa[i] - k; 103 qsort(); 104 swap(tp,rnk); 105 rnk[sa[1]] = p = 1; 106 for (int i = 2; i <= len; i++) 107 rnk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + k] == tp[sa[i] + k]) ? p : ++p; 108 } 109 } 110 int solve(int x,int y) 111 { 112 int res = 0; 113 while (str[x++] == str[y++]) 114 res++; 115 return res; 116 } 117 void get_height() 118 { 119 int cur = 0; 120 for (int i = 1; i <= len; i++) 121 { 122 if (cur != 0) 123 cur--; 124 height[rnk[i]] = cur = cur + solve(i + cur,sa[rnk[i] + 1] + cur); 125 } 126 } 127 } sf; 128 struct stable 129 { 130 int p[MAXN][30]; 131 int len; 132 void init(int _len,int *vec) 133 { 134 len = _len; 135 int tp = log2(len); 136 for (int i = 1; i <= len; i++) 137 p[i][0] = vec[i]; 138 for (int i = 1; i <= tp; i++) 139 for (int j = 1; j + uni[i] - 1 <= len; j++) 140 p[j][i] = min(p[j][i - 1],p[j + uni[i - 1]][i - 1]); 141 } 142 int querymin(int l,int r) 143 { 144 int tp = log2(r - l + 1); 145 return min(p[l][tp],p[r - uni[tp] + 1][tp]); 146 } 147 } st; 148 int tdl(int x,int lt) 149 { 150 int l = 1,r = x; 151 while (l < r) 152 { 153 int mid = l + r >> 1; 154 if (st.querymin(mid,x) >= lt) 155 r = mid; 156 else 157 l = mid + 1; 158 } 159 return l; 160 } 161 int tdr(int x,int lt) 162 { 163 int l = x,r = len; 164 while (l < r) 165 { 166 int mid = l + r + 1 >> 1; 167 if (st.querymin(x,mid) >= lt) 168 l = mid; 169 else 170 r = mid - 1; 171 } 172 return l; 173 } 174 175 int main() 176 { 177 uni[0] = 1; 178 for (int i = 1; i <= 25; i++) 179 uni[i] = uni[i - 1] << 1; 180 for(scanf("%d",&T); T != 0; T--) 181 { 182 scanf("%d%d",&len,&q); 183 scanf("%s",str + 1); 184 sf.clear(); 185 sf.build(len,str); 186 sf.get_sa(); 187 sf.get_height(); 188 st.init(sf.len,sf.height); 189 kt.clear(); 190 kt.build(len,sf.sa); 191 int l,r,k,tl,tr; 192 for (int i = 1; i <= q; i++) 193 { 194 scanf("%d%d%d",&l,&r,&k); 195 if (sf.height[sf.rnk[l] - 1] < r - l + 1) 196 tl = sf.rnk[l]; 197 else 198 tl = tdl(sf.rnk[l] - 1,r - l + 1); 199 if (sf.height[sf.rnk[l]] < r - l + 1) 200 tr = sf.rnk[l]; 201 else 202 tr = tdr(sf.rnk[l],r - l + 1) + 1; 203 if (k > kt.s[kt.root[tr]] - kt.s[kt.root[tl - 1]]) 204 printf("-1\n"); 205 else 206 printf("%d\n",kt.ask(1,len,k,kt.root[tl - 1],kt.root[tr])); 207 } 208 } 209 return 0; 210 }
心之所动 且就随缘去吧