题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704

题意为查询子串s[l...r]第k次出现的位置。

写完博客后5分钟的更新


写完博客才发现这份代码和杭电的代码查重了....

为什么会变成这样呢?是我先交的,明明是我先交的…


激动!!第一次网络赛做出这种(板子)题。

首先求一下后缀数组的Height,我们知道Height数组表示两个排名相邻的后缀的最长公共前缀,则Height数组的区间最小值即为区间排名相邻的后缀的最长公共前缀。

我们想知道那些后缀包含了所查询的区间s[l...r]这样的前缀,则先找到s[l...n]这个后缀的排名,然后在包含这个排名的Height数组中找到最长的区间,且该区间最小值要大于等于r-l+1。即该区间内的后缀的最长公共前缀包含s[l...r]。

找这个最长的区间就可以分别二分左右端点,判断用ST表预处理Height数组,然后O(1)查询即可。

然后我们的任务就是在这个区间内找到第k小的位置。这个问题就可以对后缀数组的排名建主席树。然后查询即可。

  1. #include<bits/stdc++.h>
  2. #define lson l,mid,i<<1
  3. #define rson mid+1,r,i<<1|1
  4. using namespace std;
  5. typedef long long ll;
  6. typedef unsigned long long ull;
  7. const int maxn = 2e5 + ;
  8. int sa[maxn], tax[maxn], rak[maxn], tp[maxn], Height[maxn], lg[maxn];
  9. int dp[maxn][];
  10. int root[maxn], ls[maxn * ], rs[maxn * ], val[maxn * ], cnt;
  11. char s[maxn];
  12. void Qsort(int n, int m) {
  13. for (int i = ; i < m; i++) tax[i] = ;
  14. for (int i = ; i < n; i++) tax[rak[i]]++;
  15. for (int i = ; i < m; i++) tax[i] += tax[i - ];
  16. for (int i = n - ; i >= ; i--) sa[--tax[rak[tp[i]]]] = tp[i];
  17. }
  18. void suffix(int n, int m) {//n为原串长度+1,m为原串的种类
  19. for (int i = ; i < n; i++)
  20. rak[i] = s[i], tp[i] = i;
  21. Qsort(n, m);
  22. //debug();
  23. for (int k = ; k <= n; k <<= ) {
  24. int p = ;
  25. for (int i = n - k; i < n; i++) tp[p++] = i;
  26. for (int i = ; i < n; i++) if (sa[i] >= k) tp[p++] = sa[i] - k;
  27. Qsort(n, m);
  28. swap(rak, tp);
  29. p = ;
  30. rak[sa[]] = ;
  31. for (int i = ; i < n; i++)
  32. rak[sa[i]] = (tp[sa[i - ]] == tp[sa[i]] && tp[sa[i - ] + k] == tp[sa[i] + k]) ? p - : p++;
  33. if (p >= n)
  34. break;
  35. m = p;
  36. }
  37. }
  38. void getH(int n) {
  39. int j, k = ;
  40. for (int i = ; i <= n; i++)
  41. rak[sa[i]] = i;
  42. for (int i = ; i < n; i++) {
  43. if (k)k--;
  44. j = sa[rak[i] - ];
  45. while (s[i + k] == s[j + k])
  46. k++;
  47. Height[rak[i]] = k;
  48. }
  49. }
  50. void RMQ(int n) {
  51. for (int i = ; i <= n; i++)
  52. dp[i][] = Height[i];
  53. for (int j = ; ( << j) <= n; j++) {
  54. for (int i = ; i + ( << j) - <= n; i++)
  55. dp[i][j] = min(dp[i][j - ], dp[i + ( << (j - ))][j - ]);
  56. }
  57. lg[] = -;
  58. for (int i = ; i <= n; i++) {
  59. if ((i&(i - )) == )
  60. lg[i] = lg[i - ] + ;
  61. else
  62. lg[i] = lg[i - ];
  63. }
  64. }
  65. int queryR(int l, int r) {
  66. int k = lg[r - l + ];
  67. return min(dp[l][k], dp[r - ( << k) + ][k]);
  68. }
  69. void build(int l, int r, int &i) {
  70. i = ++cnt;
  71. val[i] = ;
  72. if (l == r)
  73. return;
  74. int mid = l + r >> ;
  75. build(l, mid, ls[i]);
  76. build(mid + , r, rs[i]);
  77. }
  78. void update(int k, int l, int r, int &i) {
  79. ls[++cnt] = ls[i], rs[cnt] = rs[i], val[cnt] = val[i] + ;
  80. i = cnt;
  81. if (l == r)
  82. return;
  83. int mid = l + r >> ;
  84. if (k <= mid)
  85. update(k, l, mid, ls[i]);
  86. else
  87. update(k, mid + , r, rs[i]);
  88. }
  89. int query(int u, int v, int k, int l, int r) {
  90. if (l == r)
  91. return l;
  92. int x = val[ls[v]] - val[ls[u]];
  93. int mid = l + r >> ;
  94. if (x >= k)
  95. return query(ls[u], ls[v], k, l, mid);
  96. else
  97. return query(rs[u], rs[v], k - x, mid + , r);
  98. }
  99. int main() {
  100. int t;
  101. scanf("%d", &t);
  102. while (t--) {
  103. int n, q, cnt = ;
  104. scanf("%d%d", &n, &q);
  105. scanf("%s", s);
  106. suffix(n + , );
  107. getH(n);
  108. for (int i = ; i <= n; i++)
  109. ++sa[i];
  110. for (int i = n; i >= ; i--)
  111. rak[i] = rak[i - ];
  112. RMQ(n);
  113. build(, n, root[]);
  114. for (int i = ; i <= n; i++) {
  115. root[i] = root[i - ];
  116. update(sa[i], , n, root[i]);
  117. }
  118. //for (int i = 1; i <= n; i++)
  119. // printf("%d%c", sa[i], i == n ? '\n' : ' ');
  120. //for (int i = 1; i <= n; i++)
  121. // printf("%d%c", rak[i], i == n ? '\n' : ' ');
  122. //for (int i = 1; i <= n; i++)
  123. // printf("%d%c", Height[i], i == n ? '\n' : ' ');
  124. while (q--) {
  125. int l, r, k, len;
  126. scanf("%d%d%d", &l, &r, &k);
  127. len = r - l + ;
  128. int x = rak[l], y = rak[l];
  129. int L = x + , R = n;
  130. while (L <= R) {
  131. int mid = L + R >> ;
  132. if (queryR(L, mid) >= len)
  133. y = mid, L = mid + ;
  134. else
  135. R = mid - ;
  136. }
  137. L = , R = x;
  138. while (L <= R) {
  139. int mid = L + R >> ;
  140. if (queryR(mid, R) >= len)
  141. x = mid - , R = mid - ;
  142. else
  143. L = mid + ;
  144. }
  145. //cout << x << " " << y << endl;
  146. if (y - x + < k)
  147. printf("-1\n");
  148. else
  149. printf("%d\n", query(root[x - ], root[y], k, , n));
  150. }
  151. }
  152. }

[2019CCPC网络赛][hdu6704]K-th occurrence(后缀数组&&主席树)的更多相关文章

  1. HDU - 6704 K-th occurrence (后缀数组+主席树/后缀自动机+线段树合并+倍增)

    题意:给你一个长度为n的字符串和m组询问,每组询问给出l,r,k,求s[l,r]的第k次出现的左端点. 解法一: 求出后缀数组,按照排名建主席树,对于每组询问二分或倍增找出主席树上所对应的的左右端点, ...

  2. HDU-6704 K-th occurrence(后缀数组+主席树)

    题意 给一个长度为n的字符串,Q次询问,每次询问\((l,r,k)\) , 回答子串\(s_ls_{l+1}\cdots s_r\) 第\(k\) 次出现的位置,若不存在输出-1.\(n\le 1e5 ...

  3. 计蒜客 2019南昌邀请网络赛J Distance on the tree(主席树)题解

    题意:给出一棵树,给出每条边的权值,现在给出m个询问,要你每次输出u~v的最短路径中,边权 <= k 的边有几条 思路:当时网络赛的时候没学过主席树,现在补上.先树上建主席树,然后把边权交给子节 ...

  4. BZOJ3473:字符串(后缀数组,主席树,二分,ST表)

    Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...

  5. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

  6. [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...

  7. LOJ_#2720. 「NOI2018」你的名字 _后缀数组+主席树+倍增

    题面: https://loj.ac/problem/2720 考虑枚举T串的每个后缀i,我们要做两件事. 一.统计有多少子串[i,j]在S中要求位置出现. 二.去重. 第二步好做,相当于在后缀数组上 ...

  8. P5346 【XR-1】柯南家族(后缀数组+主席树)

    题目 P5346 [XR-1]柯南家族 做法 聪明性是具有传递性的,且排列是固定的 那么先预处理出每个点的名次,用主席树维护\(k\)大值 一眼平衡树,遍历的同时插入\(O(log^2n)\),总时间 ...

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

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

随机推荐

  1. java 中的编码

    1.1字节=8位,1024字节=1KB2.16进制0x12345678,其二进制为00010010 00110100 01010110 01111000共4字节3.字节序:两个或多个字节存放的先后顺序 ...

  2. 模拟输入(ADC-A0)

    ESP8266具有内置的10位ADC,只有一个ADC通道(A0引脚),即只有一个ADC输入引脚可读取来自外部器件的模拟电压 ESP8266上的ADC通道和芯片供电电压复用,也就是说我们可以将其设置为测 ...

  3. 【leetcode】1129. Shortest Path with Alternating Colors

    题目如下: Consider a directed graph, with nodes labelled 0, 1, ..., n-1.  In this graph, each edge is ei ...

  4. luogu 2219[HAOI2007]修筑绿化带 单调队列

    Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in",& ...

  5. POJ 2385 Apple Catching ( 经典DP )

    题意 : 有两颗苹果树,在 1~T 的时间内会有两颗中的其中一颗落下一颗苹果,一头奶牛想要获取最多的苹果,但是它能够在树间转移的次数为 W 且奶牛一开始是在第一颗树下,请编程算出最多的奶牛获得的苹果数 ...

  6. 特征提取算法(1)——纹理特征提取算法LBP

    模式识别中进行匹配识别或者分类器分类识别时,判断的依据就是图像特征.用提取的特征表示整幅图像内容,根据特征匹配或者分类图像目标. 常见的特征提取算法主要分为以下3类: 基于颜色特征:如颜色直方图.颜色 ...

  7. [CSP-S模拟测试]:big(Trie树+贪心)

    题目描述 你需要在$[0,2^n)$中选一个整数$x$,接着把$x$依次异或$m$个整数$a_1~a_m$.在你选出$x$后,你的对手需要选择恰好一个时刻(刚选完数时.异或一些数后或是最后),将$x$ ...

  8. bootstrap动态调用select下拉框

    html代码: <label for="classify" class="col-sm-2 control-label">填报部门:</lab ...

  9. 阿里云安装配置yarn,Nginx

    1.和npm 相比yarn 的优势在于 1.比npm快.npm是一个个安装包,yarn 是并行安装. 2.npm 可能会有情况 同样的 package.json 文件在不同的机器上安装的包不一样.导致 ...

  10. HDU6599 (字符串哈希+回文自动机)

    题意: 求有多少个回文串的前⌈len/2⌉个字符也是回文串.(两组解可重复)将这些回文串按长度分类,分别输出长度为1,2,...,n的合法串的数量. 题解:https://www.cnblogs.co ...