HDU-6704 K-th occurrence
Description
You are given a string S consisting of only lowercase english letters and some queries.
For each query (l,r,k), please output the starting position of the k-th occurence of the substring $S_lS_{l+1}...S_r $in S.
Input
The first line contains an integer T(1≤T≤20), denoting the number of test cases.
The first line of each test case contains two integer N(1≤N≤\(10^5\)),Q(1≤Q≤\(10^5\)), denoting the length of S and the number of queries.
The second line of each test case contains a string S(|S|=N) consisting of only lowercase english letters.
Then Q lines follow, each line contains three integer l,r(1≤l≤r≤N) and k(1≤k≤N), denoting a query.
There are at most 5 testcases which N is greater than \(10^3\).
Output
For each query, output the starting position of the k-th occurence of the given substring.
If such position don't exists, output −1 instead.
Sample Input
2
12 6
aaabaabaaaab
3 3 4
2 3 2
7 8 3
3 4 2
1 4 2
8 12 1
1 1
a
1 1 1
Sample Output
5
2
-1
6
9
8
1
题解
给定一个字符串,每次询问[l,r]的字符串第k次出现的位置,没有则输出-1
后缀数组理解深刻的话应该可以秒掉这道题
首先,height[i]表示排名第i位的和第i-1位的最长公共前缀,所以我们要找某个子串出现的所有位置,只需要在height数组中二分,询问的字串所处后缀的排名即为\(rk[l]\),那么我们从\(rk[l]\)开始向上向下二分,让这段的区间height最小值大于r-l+1,那么他们就都有r-l+1的最长公共前缀,我们找出这个边界后,用主席树求这个区间中sa数组的第k大即可。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
char s[N];
int x[N], y[N], c[N], sa[N], rk[N], height[N];
int n, m, q;
void tsort() {
for (int i = 0; i <= m; i++) c[i] = 0;
for (int i = 1; i <= n; i++) c[x[i]]++;
for (int i = 2; i <= m; i++) c[i] += c[i - 1];
for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i];
}
void get_sa() {
memset(c, 0, sizeof(c));
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for (int i = 1; i <= n; i++) x[i] = s[i], y[i] = i;
tsort();
for (int k = 1; k <= n; k <<= 1) {
int num = 0;
for (int i = n - k + 1; i <= n; i++) y[++num] = i;
for (int i = 1; i <= n; i++) if (sa[i] > k) y[++num] = sa[i] - k;
tsort();
swap(x, y);
x[sa[1]] = 1;
num = 1;
for (int i = 2; i <= n; i++)
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
if (num == n) break;
m = num;
}
}
void get_h() {
int k = 0;
for (int i = 1; i <= n; i++) rk[sa[i]] = i;
for (int i = 1; i <= n; i++) {
if (rk[i] == 1) continue;
if (k) k--;
int j = sa[rk[i] - 1];
while (s[i + k] == s[j + k]) k++;
height[rk[i]] = k;
}
}
int st[N][20], lg2[N];
void ST() {
for (int i = 1; i <= n; i++) {
st[i][0] = height[i];
}
for (int j = 1; (1 << j) <= n; j++) {
for (int i = 1; (i + (1 << j) - 1) <= n; i++) {
st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
for (int i = 2; i <= n; i++) {
lg2[i] = lg2[i >> 1] + 1;
}
}
int rmq(int l, int r) {
if (l > r)
return 0;
else {
int x = lg2[r - l + 1];
return min(st[l][x], st[r - (1 << x) + 1][x]);
}
}
int L[N * 40], R[N * 40], T[N], cnt;
ll sum[N * 40];
int build(int l, int r) {
int rt = ++cnt;
sum[rt] = 0;
int mid = (l + r) >> 1;
if (l < r) {
L[rt] = build(l, mid);
R[rt] = build(mid + 1, r);
}
return rt;
}
int update(int pre, int l, int r, int x) {
int rt = ++cnt;
int mid = (l + r) >> 1;
L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + 1;
if (l < r) {
if (x <= mid) L[rt] = update(L[pre], l, mid, x);
else R[rt] = update(R[pre], mid + 1, r, x);
}
return rt;
}
int query(int u, int v, int l, int r, int k) {
if (l >= r) {
return l;
}
int mid = (l + r) >> 1;
int x = sum[L[v]] - sum[L[u]];
if (x >= k) return query(L[u], L[v], l, mid, k);
else {
if (sum[R[v]] - sum[R[u]] < k - x) return -1;
return query(R[u], R[v], mid + 1, r, k - x);
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
m = 130;
scanf("%d%d", &n, &q);
scanf("%s", s + 1);
cnt = 0;
get_sa();
get_h();
ST();
T[0] = build(1, n);
for (int i = 1; i <= n; i++) {
T[i] = update(T[i - 1], 1, n, sa[i]);
}
while (q--) {
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
int tl = rk[l], tr = rk[l];
int x = 1, y = rk[l];
while (x <= y) {
int mid = (x + y) >> 1;
if (rmq(mid, rk[l]) >= r - l + 1) {
y = mid - 1;
tl = min(tl, mid - 1);//注意细节
}
else x = mid + 1;
}
x = rk[l] + 1, y = n;//注意细节
while (x <= y) {
int mid = (x + y) >> 1;
if (rmq(rk[l] + 1, mid) >= r - l + 1) {
x = mid + 1;
tr = max(tr, mid);
}
else y = mid - 1;
}
printf("%d\n", query(T[tl - 1], T[tr], 1, n, k));
}
}
return 0;
}
HDU-6704 K-th occurrence的更多相关文章
- 2019CCPC网络赛 C - K-th occurrence HDU - 6704(后缀数组+ST表+二分+主席树)
题意 求区间l,r的子串在原串中第k次出现的位置. 链接:https://vjudge.net/contest/322094#problem/C 思路 比赛的时候用后缀自动机写的,TLE到比赛结束. ...
- K-th occurrence HDU - 6704 (SA, 主席树)
大意: 给定串$s$, $q$个询问$(l,r,k)$, 求子串$s[l,r]$的第$k$次出现位置. 本来是个简单签到题, 可惜比赛的时候还没学$SA$...... 好亏啊 相同的子串在$SA$中是 ...
- HDU - 6704 K-th occurrence (后缀数组+主席树/后缀自动机+线段树合并+倍增)
题意:给你一个长度为n的字符串和m组询问,每组询问给出l,r,k,求s[l,r]的第k次出现的左端点. 解法一: 求出后缀数组,按照排名建主席树,对于每组询问二分或倍增找出主席树上所对应的的左右端点, ...
- K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)
大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...
- hdu 6704 K-th occurrence(后缀数组+可持久化线段树)
Problem Description You are given a string S consisting of only lowercase english letters and some q ...
- HDU 6704 K-th occurrence(主席树 + RMQ + 后缀数组)题解
题意: 给一个串\(S\),\(length\leq 1e5\),\(Q\leq1e5\)个询问,每次询问输出和\(S_lS_{l+1}\dots S_r\)长得一模一样的第\(k\)个子串的开头位置 ...
- HDU 5122 K.Bro Sorting(模拟——思维题详解)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5122 Problem Description Matt's friend K.Bro is an A ...
- HDU 5122 K.Bro Sorting(2014北京区域赛现场赛K题 模拟)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5122 解题报告:定义一种排序算法,每一轮可以随机找一个数,把这个数与后面的比这个数小的交换,一直往后判 ...
- HDU 5122 K.Bro Sorting
K.Bro Sorting Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others) Tot ...
- 基础题:HDU 5122 K.Bro Sorting
Matt's friend K.Bro is an ACMer.Yesterday, K.Bro learnt an algorithm: Bubble sort. Bubble sort will ...
随机推荐
- MSSQL注入--反弹注入
明明是sql注入的点,却无法进行注入,注射工具拆解的速度异常的缓慢,错误提示信息关闭,无法返回注入的结果,这个时候你便可以尝试使用反弹注入, 反弹注入需要依赖于函数opendatasource的支持, ...
- 第三次实验报告&&学习总结
实验三 String类的应用 实验目的 掌握类String类的使用: 学会使用JDK帮助文档: 实验内容 1.已知字符串:"this is a test of java".按要求执 ...
- [19/06/06-星期四] HTML基础_文本标签、列表(有序、无序、定义)、文本格式化(单位、字体、大小写、文本修饰、间距、对齐文本)
一.文本标签 em:用来表示一段内容的着重点,语气上的强调.一般显示为斜体 i:是斜体显示,和em显示效果一样.h5规定不需要着重的内容而是单纯加粗或斜体可以用i或b.用的不多 strong:用来表示 ...
- mock.js的运用
一:概念 Mock.js是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试.提供了以下模拟功能: 根据数据模板生成模拟数据 模拟 Ajax 请求,生成并返回模拟数据 基于 H ...
- 关系型数据库为什么喜欢使用B+树作为索引结构? (转)
问题1. 数据库为什么要设计索引? 图书馆存了1000W本图书,要从中找到<架构师之路>,一本本查,要查到什么时候去? 于是,图书管理员设计了一套规则: (1)一楼放历史类,二楼放文学类, ...
- CTS2018+1没去记&APIO2018+1游记
bgm Tips:想知道为什么标题不是2019吗,请看评论区 Day -2 md上午才写一道题qwq 机房里一堆dalao都回家收东西去北京了qwq,我菜死了,cts都去不了QAQ 下午晚上也才肝了两 ...
- B/S,C/S架构的区别
B/S架构:browser/server,采用的是浏览器服务器模式. C/S架构:client/server,采用的是客户端服务器模式. B/S架构,客户端是浏览器基本不需要维护,只需要维护升级服务器 ...
- 前端开发HTML&CSS入门——具体是做什么的
软件开发,一提起来感觉这个感觉这个词范围很大很广,说起来也很笼统.不知所云,开发的到底是什么?或者说开发的具体内容是什么?以前我们讲软件开发主要是分前端和后端,那前端和后端又是什么那?你可以这么通俗的 ...
- (新手入门,学习笔记)通过NPM进行Vue.js的安装
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,本文只介绍如何通过NPM进行安装Vue.js NodeJS官方网站:http://nodejs.cn/downlo ...
- wpf textblock 长文本滚动
在textblock添加滚动条 <ScrollViewer VerticalScrollBarVisibility="Auto"> <TextBlock x:Na ...