「TJOI / HEOI2016」字符串

题目描述

佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个问题。佳媛姐姐必须正确回答这 \(m\)个问题,才能打开箱子拿到礼物,升职加薪,出任 \(CEO\),嫁给高富帅,走上人生巅峰。每个问题均有 \(a,b,c,d\) 四个参数,问你子串 \(s[a…b]\) 的所有子串和 \(s[c…d]\) 的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

\(1 \leq n, m \leq 100000, \ a \leq b, \ c \leq d, \ 1 \leq a, b, c, d \leq n\)

### 解题思路 :

写\(sam\)是肯定会去写的,这样才学的了字符串,后缀数组又不会用,\(sam\)套上数据结构的感觉就像回家一样

里面又能剖分又能线段树合并,调试又好调,我爱死这种写法了 \(qwq\)

问题求一个字符串的前缀最多能和另一个字符串的所有子串匹配多少, 不妨二分答案判断这个前缀是否在这些子串里出现过

考虑对母串建 \(sam\) ,求出原串中每一个后缀在 \(sam\) 上的对应节点,那么对于需要\(check\) 的前缀 \([c, c + len -1]\) ,可以快速倍增找到其在前缀树上对应的节点

设找到的节点为 \(u\) ,问题就转化为 \(u\) 的 \(right\) 集合中,是否存在一个来自于 \([a+len-1, b]\) 的后缀

所以,直接大力线段树合并维护 \(parent\) 树上每个节点的 \(right\) 集合即可,查询只需要判断对应线段树的 \([a+len-1, b]\) 的和是否 \(>=1\),复杂度是 \(O(mlog^2n)\)

  1. /*program by mangoyang*/
  2. #include<bits/stdc++.h>
  3. #define inf (0x7f7f7f7f)
  4. #define Max(a, b) ((a) > (b) ? (a) : (b))
  5. #define Min(a, b) ((a) < (b) ? (a) : (b))
  6. #define N (200005)
  7. typedef long long ll;
  8. using namespace std;
  9. template <class T>
  10. inline void read(T &x){
  11. int f = 0, ch = 0; x = 0;
  12. for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
  13. for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
  14. if(f) x = -x;
  15. }
  16. char s[N]; int n, m;
  17. struct Segment_Tree{
  18. int sum[N*25], lc[N*25], rc[N*25], cnt;
  19. inline void modify(int &u, int l, int r, int pos){
  20. u = ++cnt;
  21. if(l == r) return (void) (sum[u]++);
  22. int mid = l + r >> 1;
  23. if(pos <= mid) modify(lc[u], l, mid, pos);
  24. else modify(rc[u], mid + 1, r, pos);
  25. sum[u] = sum[lc[u]] + sum[rc[u]];
  26. }
  27. inline int merge(int x, int y, int l, int r){
  28. if(!x || !y) return x + y; int o = ++cnt;
  29. if(l == r) sum[o] = sum[x] + sum[y];
  30. else{
  31. int mid = l + r >> 1;
  32. lc[o] = merge(lc[x], lc[y], l, mid);
  33. rc[o] = merge(rc[x], rc[y], mid + 1, r);
  34. sum[o] = sum[lc[o]] + sum[rc[o]];
  35. }
  36. return o;
  37. }
  38. inline int query(int u, int l, int r, int L, int R){
  39. if(!u) return 0;
  40. if(l >= L && r <= R) return sum[u];
  41. int mid = l + r >> 1, res = 0;
  42. if(L <= mid) res += query(lc[u], l, mid, L, R);
  43. if(mid < R) res += query(rc[u], mid + 1, r, L, R);
  44. return res;
  45. }
  46. }Seg;
  47. struct Suffix_Automaton{
  48. int f[N][23], rt[N<<1], buf[N], a[N];
  49. int ch[N][26], fa[N], dep[N], pos[N], tail, size;
  50. inline Suffix_Automaton(){ tail = size = 1; }
  51. inline int newnode(int x){ dep[++size] = x; return size; }
  52. inline void ins(int c, int id){
  53. int p = tail, np = newnode(dep[p] + 1);
  54. Seg.modify(rt[np], 1, n, id), pos[id] = np;
  55. for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
  56. if(!p) return (void) (fa[np] = 1, tail = np);
  57. int q = ch[p][c];
  58. if(dep[q] == dep[p] + 1) fa[np] = q;
  59. else{
  60. int nq = newnode(dep[p] + 1);
  61. fa[nq] = fa[q], fa[q] = fa[np] = nq;
  62. for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
  63. for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
  64. }tail = np;
  65. }
  66. inline void prepare(){
  67. for(int i = 1; i <= size; i++) f[i][0] = fa[i];
  68. for(int j = 1; j <= 22; j++)
  69. for(int i = 1; i <= size; i++) f[i][j] = f[f[i][j-1]][j-1];
  70. for(int i = 1; i <= size; i++) buf[dep[i]]++;
  71. for(int i = 1; i <= size; i++) buf[i] += buf[i-1];
  72. for(int i = 1; i <= size; i++) a[buf[dep[i]]--] = i;
  73. for(int i = size; i >= 2; i--){
  74. int u = a[i];
  75. rt[fa[u]] = Seg.merge(rt[u], rt[fa[u]], 1, n);
  76. }
  77. }
  78. inline bool check(int x, int len, int l, int r){
  79. x = pos[x];
  80. for(int i = 22; i >= 0; i--) if(dep[f[x][i]] >= len) x = f[x][i];
  81. return Seg.query(rt[x], 1, n, l, r) >= 1;
  82. }
  83. }van;
  84. inline int solve(int a, int b, int c, int d){
  85. int l = 1, r = min(b - a + 1, d - c + 1), ans = 0;
  86. while(l <= r){
  87. int mid = l + r >> 1;
  88. if(van.check(c + mid - 1, mid, a + mid - 1, b))
  89. ans = mid, l = mid + 1;
  90. else r = mid - 1;
  91. }
  92. return ans;
  93. }
  94. int main(){
  95. read(n), read(m), scanf("%s", s + 1);
  96. for(int i = 1; i <= n; i++) van.ins(s[i] - 'a', i);
  97. van.prepare();
  98. for(int i = 1; i <= m; i++){
  99. int a, b, c, d;
  100. read(a), read(b), read(c), read(d);
  101. printf("%d\n", solve(a, b, c, d));
  102. }
  103. return 0;
  104. }

「TJOI / HEOI2016」字符串的更多相关文章

  1. loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增

    题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...

  2. 【LOJ】#2059. 「TJOI / HEOI2016」字符串

    题解 我们冷静一下,先画一棵后缀树 然后发现我们要给c和d这一段区间在[a,b]这一段开头的串里找lcp 而lcp呢,就是c点的祖先的到根的一段,假如这个祖先的子树里有[a,b - dis[u] + ...

  3. loj2059 「TJOI / HEOI2016」字符串

    字符串好难啊不会啊 #include <iostream> #include <cstdio> using namespace std; int n, m, rnk[10000 ...

  4. loj#2054. 「TJOI / HEOI2016」树

    题目链接 loj#2054. 「TJOI / HEOI2016」树 题解 每次标记覆盖整棵字数,子树维护对于标记深度取max dfs序+线段树维护一下 代码 #include<cstdio> ...

  5. AC日记——#2054. 「TJOI / HEOI2016」树

    #2054. 「TJOI / HEOI2016」树 思路: 线段树: 代码: #include <cstdio> #include <cstring> #include < ...

  6. AC日记——#2057. 「TJOI / HEOI2016」游戏 LOJ

    #2057. 「TJOI / HEOI2016」游戏 思路: 最大流: 代码: #include <cstdio> #include <cstring> #include &l ...

  7. loj #2055. 「TJOI / HEOI2016」排序

    #2055. 「TJOI / HEOI2016」排序   题目描述 在 2016 年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他. 这个 ...

  8. loj2058 「TJOI / HEOI2016」求和 NTT

    loj2058 「TJOI / HEOI2016」求和 NTT 链接 loj 思路 \[S(i,j)=\frac{1}{j!}\sum\limits_{k=0}^{j}(-1)^{k}C_{j}^{k ...

  9. LOJ #2058「TJOI / HEOI2016」求和

    不错的推柿子题 LOJ #2058 题意:求$\sum\limits_{i=0}^n\sum\limits_{j=0}^nS(i,j)·2^j·j!$其中$ S(n,m)$是第二类斯特林数 $ Sol ...

随机推荐

  1. navicat 连接Oracle 报错:Cannot load OCI DLL, 126

    1.64位win7 安装了oracle11g 使用Navicat for Oracle cannot load OCI DLL,126 解决方法:navicat 菜单中 -工具->选项-> ...

  2. sphinx搜索 笔记

    架构图: 安装sphinx,见文章http://my.oschina.net/ptk/blog/495435 sphinx关键的配置文件.在里面写查询的sql. 两个关键命令:indexer生成查询索 ...

  3. Java IO详解(三)------字节输入输出流

    File 类的介绍:http://www.cnblogs.com/ysocean/p/6851878.html Java IO 流的分类介绍:http://www.cnblogs.com/ysocea ...

  4. Base64Util 工具类

    package com.org.utils; import java.io.ByteArrayOutputStream; public class Base64Util { private stati ...

  5. day 11 前方高能-迭代器

    第一类对象 -----函数名  == 变量名 函数对象可以像变量一样进行赋值 还可以作为列表的元素进行使用 可以作为返回值返回 def wrapper():     def inner():      ...

  6. 大数据入门第十四天——Hbase详解(一)入门与安装配置

    一.概述 1.什么是Hbase 根据官网:https://hbase.apache.org/ Apache HBase™ is the Hadoop database, a distributed, ...

  7. 20155220 《网络对抗》Exp 8 Web基础

    20155220 <网络对抗>Exp 8 Web基础 基础问题回答 实践内容 1.Web前端HTML 配置环境 正常安装.启动Apache 安装:sudo apt-get install ...

  8. PHP和PHPINFO

    PHP开放源码和跨越平台,PHP可以运行在WINDOWS和多种版本的LINUX上.它不需要任何预先处理而快速反馈结果,它也不需要mod_perl的调整来使您的服务器的内存映象减小.PHP消耗的资源较少 ...

  9. [PLC]ST语言四:INV_MEP_MEF_PLS_PLF_MC_MCR

    一:INV_MEP_MEF_PLS_PLF_MC_MCR 说明:简单的顺控指令不做其他说明. 控制要求:无 编程梯形图: 结构化编程ST语言: (*运算结果的反转INV(EN);*) M415:=in ...

  10. pycharm常用的一些快捷键

    1.编辑(Editing) Ctrl + Space 基本的代码完成(类.方法.属性)Ctrl + Alt + Space 快速导入任意类Ctrl + Shift + Enter 语句完成Ctrl + ...