大意: 给定串$s$, $q$个询问$(l,r,k)$, 求子串$s[l,r]$的第$k$次出现位置.

本来是个简单签到题, 可惜比赛的时候还没学$SA$...... 好亏啊

相同的子串在$SA$中是一定是连续的一段$[L,R]$

满足对于$L<i\le R$都有$h_i\ge r-l+1$

可以先用线段树二分出$L,R$, 然后主席树查询第$k$大即可

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstdio>
  4. #include <cstring>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. #define PER(i,a,n) for(int i=n;i>=a;--i)
  7. #define lc (o<<1)
  8. #define rc (lc|1)
  9. #define mid ((l+r)>>1)
  10. #define ls lc,l,mid
  11. #define rs rc,mid+1,r
  12. using namespace std;
  13. const int N = 1e5+10;
  14. int n, q, tot, a[N], T[N];
  15. struct {int l,r,v;} tr[N*40];
  16. char s[N];
  17. int c[N],rk[N],h[N],sa[N],mi[N<<2];
  18.  
  19. void build(int *a, int n, int m) {
  20. a[n+1] = 0;
  21. int i,*x=rk,*y=h;
  22. for(i=1;i<=m;i++) c[i]=0;
  23. for(i=1;i<=n;i++) c[x[i]=a[i]]++;
  24. for(i=1;i<=m;i++) c[i]+=c[i-1];
  25. for(i=n;i;i--) sa[c[x[i]]--]=i;
  26. for(int k=1,p;k<=n;k<<=1) {
  27. p=0;
  28. for(i=n-k+1;i<=n;i++) y[++p]=i;
  29. for(i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
  30. for(i=1;i<=m;i++) c[i]=0;
  31. for(i=1;i<=n;i++) c[x[y[i]]]++;
  32. for(i=1;i<=m;i++) c[i]+=c[i-1];
  33. for(i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
  34. swap(x,y); x[sa[1]]=1; p=1;
  35. for(i=2;i<=n;i++)
  36. x[sa[i]]=(y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?p:++p;
  37. if(p==n) break; m=p;
  38. }
  39. for(i=1;i<=n;i++) rk[sa[i]]=i;
  40. for(int i=1,j,k=0;i<=n;i++){
  41. if(k) k--;
  42. j=sa[rk[i]-1];
  43. while (a[i+k]==a[j+k]) k++;
  44. h[rk[i]] = k;
  45. }
  46. }
  47. //求最小的位置p, 使得[p,x]的最小值>=v
  48. int find1(int o, int l, int r, int x, int v) {
  49. if (r<=x) {
  50. if (l==r) return mi[o]>=v?l:-1;
  51. if (mi[rc]<v) return find1(rs,x,v);
  52. int t = find1(ls,x,v);
  53. return t==-1?mid+1:t;
  54. }
  55. if (mid>=x) return find1(ls,x,v);
  56. int R = find1(rs,x,v);
  57. if (R==-1||R>mid+1) return R;
  58. int L = find1(ls,x,v);
  59. return L==-1?R:L;
  60. }
  61. //求找最大的位置p, 使得[x,p]的最小值>=v
  62. int find2(int o, int l, int r, int x, int v) {
  63. if (x<=l) {
  64. if (l==r) return mi[o]>=v?l:-1;
  65. if (mi[lc]<v) return find2(ls,x,v);
  66. int t = find2(rs,x,v);
  67. return t==-1?mid:t;
  68. }
  69. if (mid<x) return find2(rs,x,v);
  70. int L = find2(ls,x,v);
  71. if (L==-1||L<mid) return L;
  72. int R = find2(rs,x,v);
  73. return R==-1?L:R;
  74. }
  75. int query(int u, int v, int l, int r, int k) {
  76. if (l==r) return l;
  77. int s = tr[tr[v].l].v-tr[tr[u].l].v;
  78. if (s>=k) return query(tr[u].l,tr[v].l,l,mid,k);
  79. return query(tr[u].r,tr[v].r,mid+1,r,k-s);
  80. }
  81. void add(int &o, int l, int r, int x) {
  82. tr[++tot]=tr[o],o=tot,++tr[o].v;
  83. if (l!=r) mid>=x?add(tr[o].l,l,mid,x):add(tr[o].r,mid+1,r,x);
  84. }
  85. int query(int p, int len, int k) {
  86. int l = p>1?find1(1,2,n,p,len)-1:1;
  87. int r = p<n?find2(1,2,n,p+1,len):n;
  88. if (l<0) l = p;
  89. if (r<0) r = p;
  90. if (r-l+1>=k) return query(T[l-1],T[r],1,n,k);
  91. return -1;
  92. }
  93. void build2(int o, int l, int r) {
  94. if (l==r) return mi[o]=h[l],void();
  95. build2(ls),build2(rs);
  96. mi[o]=min(mi[lc],mi[rc]);
  97. }
  98. void brute_force() {
  99. while (q--) {
  100. int l, r, k;
  101. scanf("%d%d%d",&l,&r,&k);
  102. string g(s+l,s+r+1);
  103. int pos = -1, cnt = 0;
  104. REP(i,1,n) if (string(s+i,s+i+r-l+1)==g) {
  105. if (++cnt==k) {
  106. pos = i; break;
  107. }
  108. }
  109. printf("%d\n", pos);
  110. }
  111. }
  112. int main() {
  113. int t;
  114. scanf("%d", &t);
  115. while (t--) {
  116. scanf("%d%d%s", &n, &q, s+1);
  117. if (n<=10) {brute_force();continue;}
  118. REP(i,1,n) a[i]=s[i]-'a'+1;
  119. build(a,n,26);
  120. build2(1,2,n);
  121. REP(i,1,n) {
  122. T[i] = T[i-1];
  123. add(T[i],1,n,sa[i]);
  124. }
  125. while (q--) {
  126. int l, r, k;
  127. scanf("%d%d%d", &l, &r, &k);
  128. int len = r-l+1;
  129. printf("%d\n", query(rk[l],r-l+1,k));
  130. }
  131. REP(i,0,n) T[i]=0;
  132. while (tot) tr[tot].l=tr[tot].r=tr[tot].v=0,--tot;
  133. }
  134. }

K-th occurrence HDU - 6704 (SA, 主席树)的更多相关文章

  1. 2019CCPC网络赛 C - K-th occurrence HDU - 6704(后缀数组+ST表+二分+主席树)

    题意 求区间l,r的子串在原串中第k次出现的位置. 链接:https://vjudge.net/contest/322094#problem/C 思路 比赛的时候用后缀自动机写的,TLE到比赛结束. ...

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

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

  3. 洛谷 P4094 [HEOI2016/TJOI2016]字符串(SA+主席树)

    题面传送门 一道码农题---- u1s1 感觉这类题目都挺套路的,就挑个有代表性的题写一篇题解罢. 首先注意到答案满足可二分性,故考虑二分答案 \(mid\),转化为判定性问题. 考虑怎样检验 \(m ...

  4. Sequence II HDU - 5919(主席树)

    Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,ana1,a2,⋯,anThere are ...

  5. Super Mario HDU - 4417 (主席树)

    Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory ...

  6. 【10.10校内测试】【线段树维护第k小+删除】【lca+主席树维护前驱后驱】

    贪心思想.将a排序后,对于每一个a,找到对应的删除m个后最小的b,每次更新答案即可. 如何删除才是合法并且最优的?首先,对于排了序的a,第$i$个那么之前就应该删除前$i-1$个a对应的b.剩下$m- ...

  7. 静态区间第K小(整体二分、主席树)

    题目链接 题解 主席树入门题 但是这里给出整体二分解法 整体二分顾名思义是把所有操作放在一起二分 想想,如果求\([1-n]\)的第\(k\)小怎么二分求得? 我们可以二分答案\(k\), \(O(n ...

  8. HDU 3727 Jewel 主席树

    题意: 一开始有一个空序列,然后有下面四种操作: Insert x在序列尾部加入一个值为\(x\)的元素,而且保证序列中每个元素都互不相同. Query_1 s t k查询区间\([s,t]\)中第\ ...

  9. 2019CCPC网络预选赛 1003 K-th occurrence 后缀自动机 + 二分 + 主席树

    题意:给你一个长度为n的字符串,有m次询问,每次询问l到r的子串在原串中第k次出现的位置,如果没有输出-1.n, m均为1e5级别. 思路:后悔没学后缀数组QAQ,其实只要学过后缀数组这个题还是比较好 ...

随机推荐

  1. GIS空间分析案例教程——带背景和周围要素的逐要素导出地理

    GIS空间分析案例教程--带背景和周围要素的逐要素导出地理 商务合作,科技咨询,版权转让:向日葵,135-4855__4328,xiexiaokui#qq.com 目的:导出多边形要素类的每个要素 实 ...

  2. 002 elasticsearch中的一些概念

    在本文中,主要是ES7中的核心概念. ElasticSearch是一个实时分布式开源全文搜索和分析引擎.它可以从RESTful网络服务接口访问,并使用无模式JSON (JavaScript对象符号)文 ...

  3. 如何使能hyper-v的增强功能?

    1. 在hyper-v的设置中使能增强功能 2. 运行在hyper-v中的虚拟机(笔者使用ubuntu版本为bionic)中安装xrdp 2.1 获取安装脚本 $ git clone https:// ...

  4. c++异常——学习笔记

    1.异常 throw抛出字符串 最好的是:throw抛出对象. catch(...){} 2.使用标准异常类 #include<new> bitset 自己写一个异常 设计自己异常类 堆栈 ...

  5. IDEA使用本机指定的java环境

    IDEA使用本机指定的java环境     原文链接:https://my.oschina.net/ElEGenT/blog/3053147 idea 的安装包内有自己的jre. idea 默认使用自 ...

  6. Python之Pandas操作csv文件dataframe

    # -*- coding: utf-8 -*- # author:baoshan import pandas as pd def main(): aqi_data = pd.read_csv('chi ...

  7. Python3基础 变量命名 区分大小写

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  8. 获取Excel中的图片

    如下图,上传要获取这里面的图片,而又不能直接选择,怎么办呢? 1.首先复制一份Excel文件命名copy.xlsx 2.修改copy.xlsx文件的后缀名变成copy.rar 3.解压copy.rar ...

  9. Can't accept UDP connections java.net.BindException: Address already in use_解决方案

    一.问题描述 在Linux服务器(CentOS7系统)中配置并启动JMeter远程监控服务器资源所需的ServerAgent目录下的 startAgent.sh 文件时,系统出现异常提示,如下: [r ...

  10. LODOP粒度TableRowThickNess合并行测试

    之前的博文:LODOP打印table不切行TableRowThickNess. ,中是没有合并行等的表格,通过设置增大分页粒度,会找附近的表格线,然后根据表格线分页,避免了切行.如果有比较复杂的表格, ...