题意:

给一个串\(S\),\(length\leq 1e5\),\(Q\leq1e5\)个询问,每次询问输出和\(S_lS_{l+1}\dots S_r\)长得一模一样的第\(k\)个子串的开头位置。

思路:

用后缀数组处理一下,那么所有相同子串最后的\(sa\)都会靠在一起,所以找到对应的\(height\)位置,然后向左向右延伸直到\(LCP\)长度不足\(r-l+1\)(\(RMQ\)然后二分左右第一个长度比\(r-l+1\)小的位置),那么就找到了所有和\(S_lS_{l+1}\dots S_r\)长得一模一样的开始位置,然后在主席树上找第\(k\)大。

代码:

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ull seed = 131;
const ll MOD = 1e9;
using namespace std;
struct node{int lson, rson;int num;
}T[maxn * 40];
int root[maxn], tot;
void init(){tot = 0;memset(T, 0, sizeof(T));
}
void update(int l, int r, int &now, int pre, int pos, int v){T[++tot] = T[pre], now = tot;T[now].num += v;if(l == r) return;int m = (l + r) >> 1;if(pos <= m)update(l, m, T[now].lson, T[pre].lson, pos, v);elseupdate(m + 1, r, T[now].rson, T[pre].rson, pos, v);
}
int queryK(int l, int r, int now, int pre, int k){if(l == r) return l;int m = (l + r) >> 1, Lsum;Lsum = T[T[now].lson].num - T[T[pre].lson].num;if(Lsum >= k)return queryK(l, m, T[now].lson, T[pre].lson, k);elsereturn queryK(m + 1, r, T[now].rson, T[pre].rson, k - Lsum);
}int str[maxn];  //str[n]赋值一个最小值0,其他大于0
int t1[maxn], t2[maxn], c[maxn];
int sa[maxn];   //排名为i的后缀下标
int rk[maxn];   //后缀下标为i的排名
int height[maxn];   //sa[i]与sa[i - 1]的LCP
bool cmp(int *r, int a, int b, int l){return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *str, int n, int m){n++;int i, j, p, *x = t1, *y = t2;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[i] = str[i]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;for(j = 1; j <= n; j <<= 1){p = 0;for(i = n - j; i < n; i++) y[p++] = i;for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[y[i]]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];swap(x, y);p = 1; x[sa[0]] = 0;for(i = 1; i < n; i++)x[sa[i]] = cmp(y, sa[i - 1], sa[i], j)? p - 1 : p++;if(p >= n) break;m = p;}int k = 0;n--;for(i = 0; i <= n; i++) rk[sa[i]] = i;for(i = 0; i < n; i++){if(k) k--;j = sa[rk[i] - 1];while(str[i + k] == str[j + k]) k++;height[rk[i]] = k;}
}
int n;
int dp[maxn][20], mm[maxn];
void initRMQ(){mm[0] = -1;for(int i = 1; i <= n; i++){mm[i] = ((i & (i - 1)) == 0)? mm[i - 1] + 1 : mm[i - 1];dp[i][0] = height[i];}for(int j = 1; j <= mm[n]; j++){for(int i = 1; i + (1 << j) - 1 <= n; i++){dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);}}
}
int rmq(int st, int en){int k = mm[en - st + 1];return min(dp[st][k], dp[en - (1 << k) + 1][k]);
}
int getL(int pos, int len){int l = 2, r = pos;while(l <= r){if(l == r){if(height[l] >= len) return l - 1;return l;}int m = (l + r) >> 1;if(rmq(m + 1, r) < len){l = m + 1;}else{r = m;}}
}
int getR(int pos, int len){int l = pos, r = n;while(l <= r){if(l == r){if(height[l] >= len) return l;return l - 1;}int m = (l + r) >> 1;if(rmq(l, m) < len){r = m;}else{l = m + 1;}}
}
int m;
char s[maxn];
int main(){int T;scanf("%d", &T);while(T--){scanf("%d%d", &n, &m);scanf("%s", s);int LEN = 0;for(int i = 0; i < n; i++){str[LEN++] = s[i] - 'a' + 1;}str[LEN] = 0;da(str, LEN, 30);//        for(int i = 1; i <= n; i++){
//            printf("%2d * ", i);
//            for(int j = sa[i]; j < LEN; j++){
//                printf("%c", str[j] - 1 + 'a');
//            }
//            puts("");
//        }init();initRMQ();for(int i = 1; i <= n; i++){update(1, n, root[i], root[i - 1], sa[i] + 1, 1);}while(m--){int l, r, k;scanf("%d%d%d", &l, &r, &k);l--, r--;if(n == 1){if(k == 1) printf("1\n");else printf("-1\n");continue;}int len = r - l + 1;if(rk[l] == 1){if(height[2] < len && k == 1) printf("%d\n", l + 1);else if(height[2] < len) printf("-1\n");else{int pos = 2;int pl = getL(pos, len), pr = getR(pos, len);if(pr - pl + 1 < k) printf("-1\n");else printf("%d\n", queryK(1, n, root[pr], root[pl - 1], k));}}else if(rk[l] == n){if(height[n] < len && k == 1) printf("%d\n", l + 1);else if(height[n] < len) printf("-1\n");else{int pos = n;int pl = getL(pos, len), pr = getR(pos, len);if(pr - pl + 1 < k) printf("-1\n");else printf("%d\n", queryK(1, n, root[pr], root[pl - 1], k));}}else{if(max(height[rk[l]], height[rk[l] + 1]) < len && k == 1) printf("%d\n", l + 1);else if(max(height[rk[l]], height[rk[l] + 1]) < len) printf("-1\n");else{int pos = height[rk[l]] > height[rk[l] + 1]? rk[l] : rk[l] + 1;int pl = getL(pos, len), pr = getR(pos, len);if(pr - pl + 1 < k) printf("-1\n");else printf("%d\n", queryK(1, n, root[pr], root[pl - 1], k));}}}}return 0;
}

转载于:https://www.cnblogs.com/KirinSB/p/11424053.html

HDU 6704 K-th occurrence(主席树 + RMQ + 后缀数组)题解相关推荐

  1. 数据库应用-后缀树及后缀数组(Suffix-BäumeSuffix-Arraz)-2

    McCreight-Algorithmus 在O(n)时间内构造后缀树 基本思想 在ST中插入 suffi suff_i时,以下内容可以起到帮助作用: 1.v是ST中从根节点到叶节点i-1的一个内部节 ...

  2. 后缀树和后缀数组的一些资料收集

    后缀树(Suffix tree)是一种数据结构,能快速解决很多关于字符串的问题.后缀树的概念最早由Weiner 于1973年提出,既而由McCreight 在1976年和Ukkonen在1992年和1 ...

  3. 字符串相关处理kmp,前缀数,后缀树,后缀数组,最长回文串,最长重复字串,最长非重复字串

    1. 最长回文串 一般用后缀数组或者后缀树可以解决, 用此方法:http://blog.csdn.net/v_july_v/article/details/6897097 预处理后缀树,使得查询LCA ...

  4. K-th Closest Distance HDU - 6621(第k小绝对值+主席树+二分)

    You have an array: a1, a2, , an and you must answer for some queries. For each query, you are given ...

  5. hdu 4348 To the moon (主席树)

    版权声明:本文为博主原创文章,未经博主允许不得转载. hdu 4348 题意: 一个长度为n的数组,4种操作 : (1)C l r d:区间[l,r]中的数都加1,同时当前的时间戳加1 . (2)Q ...

  6. HDU - 6621 K-th Closest Distance——主席树+二分

    [题目描述] HDU - 6621 K-th Closest Distance [题目分析] 因为看到第kkk大的要求,刚开始的时候一直都在想怎么运用第kkk大来解决问题,但是后来看其他人的博客才发现 ...

  7. HDU - 6278 Just $h$-index主席树+二分

    HDU - 6278 Just hhh-index [题目描述] [题目分析] 题目要求在区间[l,r][l,r][l,r]内大于h的数不少于h个,对于这种最大化问题,我们应该想到二分. 最小情况显然 ...

  8. HDU 2852 KiKi's K-Number 主席树

    题意: 要求维护一个数据结构,支持下面三种操作: \(0 \, e\):插入一个值为\(e\)的元素 \(1 \, e\):删除一个值为\(e\)的元素 \(2 \, a \, k\):查询比\(a\ ...

  9. HDU - 4348 To the moon(主席树区间更新-标记永久化)

    题目链接:点击查看 题目大意:给出一个初始时长度为 n 的序列,有 m 次操作,每种操作分为下列四种类型: C l r d:新建一个继承了前一个版本的数组,并将区间 [ l , r ] 内的数字都加上 ...

  10. 字符串-后缀树和后缀数组详解

    文章目录 后缀树 后缀数组 概念 sa[] rk[] height[] 例题 HDU-1403最长公共子串 洛谷P2408 不同子串个数 HDU-5769Substring 后缀树 建议先了解一下字典 ...

最新文章

  1. 合肥工业大学—SQL Server数据库实验二:数据库架构的创建与使用
  2. Service Mesh — Overview
  3. 这几天在搞UNITY3D,感觉回到了AS2
  4. 转)SSO单点登录在互联网电商应用中的解决方案(基于CAS的改造)
  5. Mysql学习总结(8)——MySql基本查询、连接查询、子查询、正则表达查询讲解...
  6. 【Angular专题】——(1)Angular,孤傲的变革者
  7. MySQL的安全设定
  8. 过春节,坐汽车回家的朋友,注意了。。
  9. 记一次惨烈的电话面试题
  10. 《波斯王子-时之砂》精美图文攻略
  11. Git 远程仓库 git remote
  12. 陕西西安职高计算机学校有哪些,2019西安中职学校名单(含公办与民办名单)...
  13. 手机变Android麦克风,手机变麦克风
  14. 流利说 Level6 全文
  15. 修复华为移动服务器,移动app云服务器异常
  16. k8s安装 从k8s.gcr.io 拉取镜像失败
  17. 安装应用宝统一链接服务器,数据互通|安卓应用宝部分区服服务器数据互通维护公告...
  18. PHP 该网页无法正常运作情况原因记录 code 500
  19. 为什么燕子鸟纹身是如此出名
  20. 无人机航模电池上面有20C 30C,这是放电倍率

热门文章

  1. cisco接口模式转换
  2. 企业图谱强势来袭!玩转企业大数据
  3. 转Openstack Ceilometer监控项扩展
  4. Spring Data Jpa 查询返回自定义对象
  5. 在HDFS集群中优化secondary namenode到datanode1节点上,并做重启hdfs集群后,datanode1启动失败...
  6. 【WP开发】JSON数据的读与写
  7. 转载——如果让我完善几年前的一个项目,我会做哪些改进?
  8. NHibernate (一) 五部曲
  9. 对MySQL数据库日志文件进行维护
  10. 最近 搞定这5篇 java相关