题目传送门

  传送门

题目大意

  给定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 + ;
  23. const int bzmax = ;
  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[] = ;
  38. for (int i = ; i <= n; i++)
  39. log2[i] = log2[i >> ] + ;
  40. for (int i = ; i < n; i++)
  41. f[i][] = ar[i];
  42. for (int j = ; j < bzmax; j++)
  43. for (int i = ; i + ( << j) - < n; i++)
  44. f[i][j] = min(f[i][j - ], f[i + ( << (j - ))][j - ]);
  45. }
  46.  
  47. int query(int l, int r) {
  48. int d = log2[r - l + ];
  49. // int rt = min(f[l][d], f[r - (1 << d) + 1][d]);
  50. // cerr << l << " " << r << " " << rt << '\n';
  51. return min(f[l][d], f[r - ( << d) + ][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, , sizeof(sa));
  78. memset(rk, , sizeof(rk));
  79. memset(hei, , sizeof(hei));
  80. }
  81.  
  82. void radix_sort(Pair3* x, Pair3* y) {
  83. int m = max(n, );
  84. memset(cnt, , sizeof(int) * m);
  85. for (int i = ; i < n; i++)
  86. cnt[x[i].y]++;
  87. for (int i = ; i < m; i++)
  88. cnt[i] += cnt[i - ];
  89. for (int i = ; i < n; i++)
  90. y[--cnt[x[i].y]] = x[i];
  91.  
  92. memset(cnt, , sizeof(int) * m);
  93. for (int i = ; i < n; i++)
  94. cnt[y[i].x]++;
  95. for (int i = ; i < m; i++)
  96. cnt[i] += cnt[i - ];
  97. for (int i = n - ; ~i; i--)
  98. x[--cnt[y[i].x]] = y[i];
  99. }
  100.  
  101. void build() {
  102. for (int i = ; i < n; i++)
  103. rk[i] = str[i];
  104. for (int k = ; k <= n; k <<= ) {
  105. for (int i = ; 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], , i);
  109. radix_sort(T1, T2);
  110. int diff = ;
  111. rk[T1[].id] = ;
  112. for (int i = ; i < n; i++)
  113. rk[T1[i].id] = (T1[i].x == T1[i - ].x && T1[i].y == T1[i - ].y) ? (diff) : (++diff);
  114. if (diff == n)
  115. break;
  116. }
  117. for (int i = ; i < n; i++)
  118. sa[--rk[i]] = i;
  119. }
  120.  
  121. void get_height() {
  122. for (int i = , j, k = ; i < n; i++, (k) ? (k--) : ()) {
  123. if (rk[i]) {
  124. j = sa[rk[i] - ];
  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 + ;
  138. x1 = rk[x1], x2 = rk[x2];
  139. if (x1 > x2)
  140. swap(x1, x2);
  141. return st.query(x1 + , 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 + , len2= r2 - l2 + ;
  147. if (len_lcp >= len1 && len_lcp >= len2)
  148. return ;
  149. if (len_lcp < len1 && len_lcp < len2)
  150. return (str[l1 + len_lcp] < str[l2 + len_lcp]) ? (-) : ();
  151. return (len_lcp >= len1) ? (-) : ();
  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 + , 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 + )];
  177. pfill(a + , a + n + , );
  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 = ;
  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 - );
  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(), g(g) {
  212. fa = new int[(n + )];
  213. in = new int[(n + )];
  214. out = new int[(n + )];
  215. sz = new int[(n + )];
  216. zson = new int[(n + )];
  217. dep = new int[(n + )];
  218. top = new int[(n + )];
  219. dfs1(, );
  220. dfs2(, 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] + ) : ());
  229. in[p] = ++dfs_clock;
  230. this->fa[p] = fa;
  231. sz[p] = ;
  232. int mx = -, id = -, e;
  233. for (unsigned i = ; 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 = , 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 >> ];
  273. char _str[N >> ];
  274. vector<int> endpos[N >> ];
  275.  
  276. inline void init() {
  277. L = ;
  278. scanf("%d%d", &n, &K);
  279. for (int i = ; i <= n; i++) {
  280. scanf("%s", _str);
  281. if (i > ) {
  282. id[L] = -;
  283. str[L] = '#'; //"!@#$%^&*()-+"[i % 11];
  284. L += ;
  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 << ];
  301. int d[N << ];
  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] > )
  309. endpos[id[p]].push_back(curid);
  310. return curid;
  311. }
  312. for (int p = l, j, L, R, mid; p <= r; p = j + ) {
  313. L = p, R = r;
  314. char x = str[sa[p] + d[curid]];
  315. while (L <= R) {
  316. mid = (L + R) >> ;
  317. if (str[sa[mid] + d[curid]] == x)
  318. L = mid + ;
  319. else
  320. R = mid - ;
  321. }
  322. j = L - ;
  323. L = build_suffix_tree(p, j);
  324. g[curid].push_back(L);
  325. }
  326. return curid;
  327. }
  328.  
  329. int res[N << ];
  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 = ; 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(, L - );
  341.  
  342. IndexedTree it (cnt_node);
  343. Graph graph (g, cnt_node);
  344. for (int i = ; i <= n; i++) {
  345. it.add(graph.in[endpos[i][]], );
  346. for (int j = ; j < (signed) endpos[i].size(); j++) {
  347. it.add(graph.in[endpos[i][j]], );
  348. int g = graph.lca(endpos[i][j], endpos[i][j - ]);
  349. it.add(graph.in[g], -);
  350. }
  351. }
  352.  
  353. dfs(, graph, it);
  354. for (int i = , p, l; i <= n; i++) {
  355. long long ans = ;
  356. for (int j = ; 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 ;
  368. }

bzoj 3473 字符串 - 后缀数组 - 树状数组的更多相关文章

  1. AcWing:246. 区间最大公约数(线段树 + 增量数组(树状数组) + 差分序列)

    给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一: 1.“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d. 2.“Q l r”,表示询问 A[l],A[l ...

  2. BZOJ 2754 SCOI 2012 喵星球上的点名 后缀数组 树状数组

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2068  Solved: 907[Submit][St ...

  3. BZOJ 2780 Sevenk Love Oimaster (后缀自动机+树状数组+dfs序+离线)

    题目大意: 给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过 好神的一道题 对$n$个大串建出广义$SAM$,建出$parent$树 把字符串$s$放到$SAM$里跑, ...

  4. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

  5. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  6. BZOJ 2743: [HEOI2012]采花 [树状数组 | 主席树]

    题意: 查询区间中出现次数$>2$的颜色个数 一眼主席树,区间中$l \le last[i] \le r$的个数减去$l \le last[last[i]] \le r$的个数,搞两颗主席树来做 ...

  7. BZOJ.4826.[AHOI/HNOI2017]影魔(树状数组/莫队 单调栈)

    BZOJ LOJ 洛谷 之前看\(mjt\)用莫队写了,以为是一种正解,码了3h结果在LOJ T了没A= = 心态爆炸(upd:发现是用C++11(NOI)交的,用C++11交就快一倍了...) 深刻 ...

  8. bzoj 3262 陌上花开 - CDQ分治 - 树状数组

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  9. bzoj 2527 Meteors - 整体二分 - 树状数组

    Description Byteotian Interstellar Union (BIU) has recently discovered a new planet in a nearby gala ...

  10. BZOJ 1396:识别子串 SA+树状数组+单调队列

    1396: 识别子串 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 381  Solved: 243[Submit][Status][Discuss] ...

随机推荐

  1. [daily]gtk程序不跟随系统的dark主题

    问题描述: 我的系统主题是dark的.在使用mysql-workbench是,里边的一些线条就跟随了系统文字的主要使用了灰白色. 这样在白色画布里就看不见这些线条了. 方法: 设置mysql-work ...

  2. MongoDB - Indexes

    #explain command pp db[:zips].find(:state => 'MD').explain #List all indexes: db[:zips].indexes.e ...

  3. 洛谷P4640 王之财宝 [BJWC2008] 数论

    正解:容斥+Lucas+组合数学 解题报告: 传送门! 和上一篇题解的题差不多,,,双倍经验趴大概算 还是说下还是有点儿区别的来着$QwQ$ 两个小差别分别港下$QwQ$ 首先有$m-n$件是无穷个的 ...

  4. C++ opencv调用resize修改插值方式遇到的坑

    opencv提供的热死则函数原型如下:void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0 ...

  5. turtlebot3 ubuntu mate 实现vnc连接

    tuutlebot3 ubuntu mate 实现vnc连接 摘要: 在turtlebot3 安装的nbuntu mate系统实验过. 实现内容 x11vnc 安装 x11vnc自动启动 vnc分辩率 ...

  6. 学号20175313 《实现Linux下cp XXX1 XXX2的功能(二)》第九周

    目录 MyCP2 一.题目要求 二.题目理解 三.需求分析 四.设计思路 五.伪代码分析 六.代码链接 七.代码实现过程中遇到的问题 八.运行结果截图 九.心得体会 十.参考资料 MyCP2 一.题目 ...

  7. jenkins 判断某个job是否正在构建

    其实很简单,访问jenkins job的xml api或者 json api,里面有两个key叫"lastBuild"和"lastCompletedBuild" ...

  8. Scala集合Map

    在scala中Map分为可变长(mutable)和不可变长(immutable) /** * 不可变长map 长度一旦初始化,就不能在进行更改 */ // 通过箭头的方式创建map val map = ...

  9. Oracle 10053

    [10053]alter session set events '10053 trace name context forever,level 1'; <Run your SQL here;&g ...

  10. Cocos Creator 动态设置Canvas的宽度与高度,更改适配

    let c = this.node.getComponent(cc.Canvas);c.fitHeight = true;c.fitWidth = false; let h = 960 * cc.wi ...