集训讲字符串的时候我唯一想出正解的题……

链接

BZOJ 2865

题面

给出一个长度为n (n <= 5e5) 的字符串,对于每一位,求包含该位的、最短的、在原串中只出现过一次的子串。

题解

“只出现过一次”,想到后缀数组,后缀数组可以求出以第i位开头的最短的在原串中只出现过一次的子串——它的长度是min(height[rank[i]], height[rank[i] + 1) + 1。

所以我们枚举每个位置i,找到这个串,然后考虑它的贡献:

对于这个串之内的位置,答案可以用这个串的长度更新;

对于这个串右边的位置,串可以向右“延伸”直到包含该位置(延伸后的串显然也只出现过一次),所以答案可以用(该位置 - i + 1)来更新。

这两个分别用线段树维护即可。

  1. #include <cstdio>
  2. #include <cmath>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. #define enter putchar('\n')
  8. #define space putchar(' ')
  9. template <class T>
  10. void read(T &x){
  11. char c;
  12. bool op = 0;
  13. while(c = getchar(), c > '9' || c < '0')
  14. if(c == '-') op = 1;
  15. x = c - '0';
  16. while(c = getchar(), c >= '0' && c <= '9')
  17. x = x * 10 + c - '0';
  18. if(op) x = -x;
  19. }
  20. template <class T>
  21. void write(T x){
  22. if(x < 0) putchar('-'), x = -x;
  23. if(x >= 10) write(x / 10);
  24. putchar('0' + x % 10);
  25. }
  26. const int N = 500005, INF = 0x3f3f3f3f;
  27. int n, sa[N], rnk[N], buf1[N], buf2[N], buc[N], height[N];
  28. int data[2][4*N], lazy[2][4*N], pos[N];
  29. char s[N];
  30. void pushdown(int h, int k){
  31. if(lazy[h][k] == INF) return;
  32. lazy[h][k << 1] = min(lazy[h][k << 1], lazy[h][k]);
  33. lazy[h][k << 1 | 1] = min(lazy[h][k << 1 | 1], lazy[h][k]);
  34. data[h][k << 1] = min(data[h][k << 1], lazy[h][k]);
  35. data[h][k << 1 | 1] = min(data[h][k << 1 | 1], lazy[h][k]);
  36. lazy[h][k] = INF;
  37. }
  38. void modify(int h, int k, int l, int r, int ql, int qr, int x){
  39. if(ql <= l && qr >= r){
  40. data[h][k] = min(data[h][k], x);
  41. lazy[h][k] = min(lazy[h][k], x);
  42. return;
  43. }
  44. int mid = (l + r) >> 1;
  45. if(ql <= mid) modify(h, k << 1, l, mid, ql, qr, x);
  46. if(qr > mid) modify(h, k << 1 | 1, mid + 1, r, ql, qr, x);
  47. data[h][k] = min(data[h][k << 1], data[h][k << 1 | 1]);
  48. }
  49. void pushdown_all(int k, int l, int r){
  50. if(l == r) return (void)(pos[l] = k);
  51. pushdown(0, k), pushdown(1, k);
  52. int mid = (l + r) >> 1;
  53. pushdown_all(k << 1, l, mid);
  54. pushdown_all(k << 1 | 1, mid + 1, r);
  55. }
  56. void suffix_sort(){
  57. int m = 128, *x = buf1, *y = buf2;
  58. for(int i = 0; i <= m; i++) buc[i] = 0;
  59. for(int i = 1; i <= n; i++) buc[x[i] = s[i]]++;
  60. for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
  61. for(int i = n; i; i--) sa[buc[x[i]]--] = i;
  62. for(int k = 1, p = 0; k <= n && p < n; k *= 2, m = p, p = 0){
  63. for(int i = n - k + 1; i <= n; i++) y[++p] = i;
  64. for(int i = 1; i <= n; i++) if(sa[i] > k) y[++p] = sa[i] - k;
  65. for(int i = 0; i <= m; i++) buc[i] = 0;
  66. for(int i = 1; i <= n; i++) buc[x[y[i]]]++;
  67. for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
  68. for(int i = n; i; i--) sa[buc[x[y[i]]]--] = y[i];
  69. swap(x, y), x[sa[1]] = 1, p = 1;
  70. for(int i = 2; i <= n; i++)
  71. x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
  72. }
  73. for(int i = 1; i <= n; i++) rnk[sa[i]] = i;
  74. for(int i = 1, k = 0; i <= n; i++){
  75. if(rnk[i] == 1) continue;
  76. int j = sa[rnk[i] - 1];
  77. if(k) k--;
  78. while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;
  79. height[rnk[i]] = k;
  80. }
  81. }
  82. int main(){
  83. scanf("%s", s + 1);
  84. n = strlen(s + 1);
  85. suffix_sort();
  86. memset(data, INF, sizeof(data));
  87. memset(lazy, INF, sizeof(lazy));
  88. for(int i = 1; i <= n; i++){
  89. int len = max(height[rnk[i]], height[rnk[i] + 1]);
  90. if(i + len <= n) modify(0, 1, 1, n, i, i + len, len + 1);
  91. if(i + len < n) modify(1, 1, 1, n, i + len + 1, n, 1 - i);
  92. }
  93. pushdown_all(1, 1, n);
  94. for(int i = 1; i <= n; i++)
  95. write(min(data[0][pos[i]], i + data[1][pos[i]])), enter;
  96. return 0;
  97. }

BZOJ 2865 字符串识别 | 后缀数组 线段树的更多相关文章

  1. bzoj 2865 字符串识别 —— 后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 唯一出现的子串就是每个后缀除去和别的后缀最长的 LCP 之外的前缀: 所以用这个更新一 ...

  2. bzoj 2865 字符串识别——后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 做出 ht[ ] 之后,sa[ ] 上每个位置和它前面与后面取 LCP ,其中较大的长 ...

  3. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

  4. bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】

    根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[ ...

  5. BZOJ 2865 字符串识别(后缀数组+线段树)

    很容易想到只考虑后缀长度必须为\(max(height[rk[i]],height[rk[i]+1])+1\)(即\([i,i+x-1]\)代表的串只出现过一次)然后我正着做一遍反着做一遍,再取一个\ ...

  6. BZOJ 1396: 识别子串( 后缀数组 + 线段树 )

    这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...

  7. BZOJ.1396.识别子串(后缀自动机/后缀数组 线段树)

    题目链接 SAM:能成为识别子串的只有那些|right|=1的节点代表的串. 设这个节点对应原串的右端点为r[i],则如果|right[i]|=1,即\(s[\ [r_i-len_i+1,r_i-le ...

  8. BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)

    题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...

  9. 【XSY1551】往事 广义后缀数组 线段树合并

    题目大意 给你一颗trie树,令\(s_i\)为点\(i\)到根的路径上的字符组成的字符串.求\(max_{u\neq v}(LCP(s_u,s_v)+LCS(s_u,s_v))\) \(LCP=\) ...

随机推荐

  1. OO——电梯作业总结

    目录 电梯作业总结 程序结构与复杂度的分析 第一次作业 第二次作业 第三次作业 程序BUG的分析 互测 自动评测 有效性 总结 电梯作业总结 程序结构与复杂度的分析 第一次作业 1.设计思路 第一次作 ...

  2. Tomcat 动态数据库连接池

    package com.boguan.bte.util; import java.sql.Connection;import java.sql.SQLException;import java.uti ...

  3. 20155216 实验一 逆向与Bof基础

    实验一 逆向与Bof基础 一.直接修改程序机器指令,改变程序执行流程 使用 objdump -d pwn1 对pwn1文件进行反汇编. 可知main函数跳转至foo函数,先要使main函数跳转至get ...

  4. 【来龙去脉系列】AutoMapper一款自动映射框架

    前言 通常在一个应用程序中,我们开发人员会在两个不同的类型对象之间传输数据,通常我们会用DTOs(数据传输对象),View Models(视图模型),或者直接是一些从一个service或者Web AP ...

  5. 【第十一课】Tomcat原理解析【转】

    目录 一.Tomcat顶层架构 二.Tomcat顶层架构小结: 三.Connector和Container的微妙关系 四.Connector架构分析 五.Container架构分析 六.Contain ...

  6. CS100.1x-lab3_text_analysis_and_entity_resolution_student

    这次作业叫Text Analysis and Entity Resolution,比前几次作业难度要大很多.相关ipynb文件见我github. 实体解析在数据清洗和数据整合中是一个很重要,且有难度的 ...

  7. binlog2sql使用总结

    binlog2sql是大众点评开源的一款用于解析binlog的工具,在测试环境试用了下,还不错. 其具有以下功能 1. 提取SQL 2. 生成回滚SQL 关于该工具的使用方法可参考github操作文档 ...

  8. Accer 4752G添加固态硬盘 双系统

    (此文一直在草稿箱里躺了一年,略作修改后发布~) 背景:电脑是2011年年末买的,用到现在也已经5年多了,好在没坏过什么硬件,有过2年疯狂打LOL的经历,之后电脑就打不动了,FPS始终上不去,启动游戏 ...

  9. Python初学者随笔Week1

    Python从入门到放弃 本文主要是描述的是作为初学者对python学习的过程与经历分享,包括一些历程的分享与重要的时间节点记录,对于python学习的笔记与心得. 如果你也是初学者,我们可以一起学习 ...

  10. djbc

    jdbc:mysql://localhost:3306:test这句里面分如下解析:jdbc:mysql:// 是指JDBC连接方式:localhost: 是指你的本机地址:3306 SQL数据库的端 ...