bzoj 3473 字符串

题目传送门

  传送门

题目大意

  给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串

  先用奇怪的字符把所有字符串连接起来。

  建后缀树,数每个节点的子树内包含多少属于不同串的后缀。

  数这个东西,可以将每个串的后缀(被奇怪的字符分割开的地方认为它属于不同后缀)按dfs序排序,然后简单容斥就能统计出来。

  对于每个后缀,有贡献的是一个前缀,然后直接统计就行了。

Code

  1 /**
  2  * bzoj
  3  * Problem#3473
  4  * Accepted
  5  * Time: 788ms
  6  * Memory: 41208k
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstring>
 11 #include <cstdio>
 12 #include <vector>
 13 #include <cmath>
 14 using namespace std;
 15 typedef bool boolean;
 16 
 17 template <typename T>
 18 void pfill(T* pst, const T* ped, T val) {
 19     for ( ; pst != ped; *(pst++) = val);
 20 }
 21 
 22 const int N = 2e5 + 5;
 23 const int bzmax = 19;
 24 
 25 typedef class SparseTable {
 26     public:
 27         int n;
 28         int *ar;
 29         int log2[N];
 30         int f[N][bzmax];
 31 
 32         SparseTable() {    }
 33         
 34         void init(int n, int* ar) {
 35             this->n = n;
 36             this->ar = ar;
 37             log2[1] = 0;
 38             for (int i = 2; i <= n; i++)
 39                 log2[i] = log2[i >> 1] + 1;
 40             for (int i = 0; i < n; i++)
 41                 f[i][0] = ar[i];
 42             for (int j = 1; j < bzmax; j++)
 43                 for (int i = 0; i + (1 << j) - 1 < n; i++)
 44                     f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
 45         }
 46 
 47         int query(int l, int r) {
 48             int d = log2[r - l + 1];
 49 //            int rt = min(f[l][d], f[r - (1 << d) + 1][d]);
 50 //            cerr << l << " " << r << " " << rt << '
';
 51             return min(f[l][d], f[r - (1 << d) + 1][d]);
 52         }
 53 }SparseTable;
 54 
 55 typedef class Pair3 {
 56     public:
 57         int x, y, id;
 58 
 59         Pair3() {    }
 60         Pair3(int x, int y, int id):x(x), y(y), id(id) {    }
 61 }Pair3;
 62 
 63 typedef class SuffixArray {
 64     protected: 
 65         Pair3 T1[N], T2[N];
 66         int cnt[N];
 67 
 68     public:
 69         int n;
 70         char *str;
 71         int sa[N], rk[N], hei[N];
 72         SparseTable st;
 73 
 74         void set(int n, char* str) {
 75             this->n = n;
 76             this->str = str;
 77             memset(sa, 0, sizeof(sa));
 78             memset(rk, 0, sizeof(rk));
 79             memset(hei, 0, sizeof(hei));
 80         }
 81 
 82         void radix_sort(Pair3* x, Pair3* y) {
 83             int m = max(n, 256);
 84             memset(cnt, 0, sizeof(int) * m);
 85             for (int i = 0; i < n; i++)
 86                 cnt[x[i].y]++;
 87             for (int i = 1; i < m; i++)
 88                 cnt[i] += cnt[i - 1];
 89             for (int i = 0; i < n; i++)
 90                 y[--cnt[x[i].y]] = x[i];
 91 
 92             memset(cnt, 0, sizeof(int) * m);
 93             for (int i = 0; i < n; i++)
 94                 cnt[y[i].x]++;
 95             for (int i = 1; i < m; i++)
 96                 cnt[i] += cnt[i - 1];
 97             for (int i = n - 1; ~i; i--)
 98                 x[--cnt[y[i].x]] = y[i];
 99         }
100 
101         void build() {
102             for (int i = 0; i < n; i++)
103                 rk[i] = str[i];
104             for (int k = 1; k <= n; k <<= 1) {
105                 for (int i = 0; i + k < n; i++)
106                     T1[i] = Pair3(rk[i], rk[i + k], i);
107                 for (int i = n - k; i < n; i++)
108                     T1[i] = Pair3(rk[i], 0, i);
109                 radix_sort(T1, T2);
110                 int diff = 1;
111                 rk[T1[0].id] = 1;
112                 for (int i = 1; i < n; i++)
113                     rk[T1[i].id] = (T1[i].x == T1[i - 1].x && T1[i].y == T1[i - 1].y) ? (diff) : (++diff);
114                 if (diff == n)
115                     break;
116             }
117             for (int i = 0; i < n; i++)
118                 sa[--rk[i]] = i;
119         }
120 
121         void get_height() {
122             for (int i = 0, j, k = 0; i < n; i++, (k) ? (k--) : (0)) {
123                 if (rk[i]) {
124                     j = sa[rk[i] - 1];
125                     while (i + k < n && j + k < n && str[i + k] == str[j + k])    k++;
126                     hei[rk[i]] = k;
127                 }
128             }        
129         }
130 
131         void init_st() {
132             st.init(n, hei);
133         }
134 
135         int lcp(int x1, int x2) {
136             if (x1 == x2)
137                 return n - x1 + 1;
138             x1 = rk[x1], x2 = rk[x2];
139             if (x1 > x2)
140                 swap(x1, x2);
141             return st.query(x1 + 1, x2);
142         }
143         
144         int compare(int l1, int r1, int l2, int r2) {
145             int len_lcp = lcp(l1, l2);
146             int len1 = r1 - l1 + 1, len2= r2 - l2 + 1;
147             if (len_lcp >= len1 && len_lcp >= len2)
148                 return 0;
149             if (len_lcp < len1 && len_lcp < len2)
150                 return (str[l1 + len_lcp] < str[l2 + len_lcp]) ? (-1) : (1);
151             return (len_lcp >= len1) ? (-1) : (1);
152         }
153 
154         int query(int u, int v) {    // u, v -> sa
155             if (u == v)
156                 return n - sa[u];
157             return st.query(u + 1, v);
158         }
159 
160         const int& operator [] (int p) {
161             return sa[p];
162         }
163 
164         const int& operator () (int p) {
165             return hei[p];
166         }
167 } SuffixArray;
168 
169 typedef class IndexedTree {
170     public:
171         int s;
172         int *a;
173 
174         IndexedTree() {    }
175         IndexedTree(int n) : s(n) {
176             a = new int[(s + 1)];
177             pfill(a + 1, a + n + 1, 0);            
178         }
179         ~IndexedTree() {
180             delete[] a;
181         }
182 
183         void add(int idx, int val) {
184             for ( ; idx <= s; idx += (idx & (-idx)))
185                 a[idx] += val;
186         }
187 
188         int query(int idx) {
189             int rt = 0;
190             for ( ; idx; idx -= (idx & (-idx)))
191                 rt += a[idx];
192             return rt;
193         }
194 
195         int query(int l, int r) {
196             return query(r) - query(l - 1);
197         }
198 } IndexedTree;
199 
200 typedef class Graph {
201     protected:
202         int dfs_clock;
203     public:
204         vector<int>* g;
205         int *fa;
206         int *in, *out;
207         int *sz, *zson;
208         int *dep, *top;
209 
210         Graph() {    }
211         Graph(vector<int>* g, int n) : dfs_clock(0), g(g) {
212             fa = new int[(n + 1)];
213             in = new int[(n + 1)];
214             out = new int[(n + 1)];
215             sz = new int[(n + 1)];
216             zson = new int[(n + 1)];
217             dep = new int[(n + 1)];
218             top = new int[(n + 1)];
219             dfs1(1, 0);
220             dfs2(1, true);
221         }
222         ~Graph() {
223 #define rem(__) delete[] __;        
224             rem(fa) rem(in) rem(out) rem(sz) rem(zson) rem(dep) rem(top)
225         }
226 
227         void dfs1(int p, int fa) {
228             dep[p] = ((fa) ? (dep[fa] + 1) : (1));
229             in[p] = ++dfs_clock;
230             this->fa[p] = fa;
231             sz[p] = 1;
232             int mx = -1, id = -1, e;
233             for (unsigned i = 0; i < g[p].size(); i++) {
234                 e = g[p][i];
235                 dfs1(e, p);
236                 sz[p] += sz[e];
237                 if (sz[e] > mx)
238                     mx = sz[e], id = e;
239             }
240             out[p] = dfs_clock;
241             zson[p] = id;
242         }
243 
244         void dfs2(int p, boolean ontop) {
245             top[p] = ((ontop) ? (p) : (top[fa[p]]));
246             if (~zson[p])
247                 dfs2(zson[p], false);
248             for (int i = 0, e; i < (signed) g[p].size(); i++) {
249                 e = g[p][i];
250                 if (e == zson[p])
251                     continue;
252                 dfs2(e, true);
253             }
254         }
255 
256         int lca(int u, int v) {
257             while (top[u] ^ top[v]) {
258                 if (dep[top[u]] < dep[top[v]])
259                     swap(u, v);
260                 u = fa[top[u]];
261             }
262             return (dep[u] < dep[v]) ? (u) : (v);
263         }
264 } Graph;
265 
266 #define pii pair<int, int>
267 
268 int n, L, K;
269 int id[N];
270 char str[N];
271 SuffixArray sa;
272 int endp[N >> 1];
273 char _str[N >> 1];
274 vector<int> endpos[N >> 1];
275 
276 inline void init() {
277     L = 0;
278     scanf("%d%d", &n, &K);
279     for (int i = 1; i <= n; i++) {
280         scanf("%s", _str);
281         if (i > 1) {
282             id[L] = -1;
283             str[L] = '#'; //"!@#$%^&*()-+"[i % 11];
284             L += 1;
285         }
286         for (char* p = _str; *p; p++) {
287             id[L] = i;
288             str[L] = *p;
289             L++;
290         }
291         endp[i] = L; 
292     }
293     sa.set(L, str);
294     sa.build();
295     sa.get_height();
296     sa.init_st();
297 }
298 
299 int cnt_node;
300 vector<int> g[N << 1];
301 int d[N << 1];
302 
303 int build_suffix_tree(int l, int r) {
304     int curid = ++cnt_node;
305     d[curid] = sa.query(l, r);
306     if (l == r) {
307         int p = sa[l];
308         if (id[p] > 0)
309             endpos[id[p]].push_back(curid);
310         return curid;
311     }
312     for (int p = l, j, L, R, mid; p <= r; p = j + 1) {
313         L = p, R = r;
314         char x = str[sa[p] + d[curid]];
315         while (L <= R) {
316             mid = (L + R) >> 1;
317             if (str[sa[mid] + d[curid]] == x)
318                 L = mid + 1;
319             else
320                 R = mid - 1;
321         }
322         j = L - 1;
323         L = build_suffix_tree(p, j);
324         g[curid].push_back(L);
325     }
326     return curid;
327 }
328 
329 int res[N << 1];
330 void dfs(int p, Graph& G, IndexedTree& it) {
331     res[p] = (it.query(G.in[p], G.out[p]) >= K) ? (d[p]) : (res[G.fa[p]]);
332     for (int i = 0; i < (signed) g[p].size(); i++) {
333          dfs(g[p][i], G, it);        
334     }
335 }
336 
337 inline void solve() {
338     while (cnt_node)
339         g[cnt_node--].clear();
340     build_suffix_tree(0, L - 1);
341 
342     IndexedTree it (cnt_node);
343     Graph graph (g, cnt_node);
344     for (int i = 1; i <= n; i++) {
345         it.add(graph.in[endpos[i][0]], 1);        
346         for (int j = 1; j < (signed) endpos[i].size(); j++) {
347             it.add(graph.in[endpos[i][j]], 1);
348             int g = graph.lca(endpos[i][j], endpos[i][j - 1]);
349             it.add(graph.in[g], -1);
350         }
351     }
352     
353     dfs(1, graph, it);
354     for (int i = 1, p, l; i <= n; i++) {
355         long long ans = 0;
356         for (int j = 0; j < (signed) endpos[i].size(); j++) {
357             p = endpos[i][j], l = d[p];
358             ans += min(endp[i] - (L - l), res[p]);        
359         }
360         printf("%lld ", ans);
361     }
362 }
363 
364 int main() {
365     init();
366     solve();
367     return 0;
368 }
原文地址:https://www.cnblogs.com/yyf0309/p/10232222.html