Problem 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 SlSl+1...Sr 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≤105),Q(1≤Q≤105), 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 103.

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的字串的兄弟串不难想到求lcp 通过二分我们可以找到最右和最左的排名 然后我们只要用可持久线段树维护下标  然后求下标第k小的字符串即可

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const int N = 1e5+1000;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
typedef long long ll;
const ll mod = 1e9+7;
int rt[N];
struct tree{
int l,r,v,ls,rs;
}t[N<<5];
int nico;
void build(int &p,int l,int r){
p=++nico;
t[p].l=l; t[p].r=r;
if(l==r){
return ;
}
int mid=(l+r)>>1;
build(t[p].ls,l,mid);
build(t[p].rs,mid+1,r);
}
void update(int &p,int last,int x){
p=++nico;
t[p]=t[last];
t[p].v++;
if(t[p].l==t[p].r&&t[p].l==x){
t[p].v=1;
return ;
}
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid) update(t[p].ls,t[last].ls,x);
else update(t[p].rs,t[last].rs,x);
}
int query(int p,int last,int k){
if(t[p].l==t[p].r){
return t[p].l;
}
int tmp=t[t[p].ls].v-t[t[last].ls].v;
int mid=(t[p].l+t[p].r)>>1;
if(tmp>=k) return query(t[p].ls,t[last].ls,k);
else return query(t[p].rs,t[last].rs,k-tmp);
}
struct S_array{
int s[N],sa[N],t[N],t2[N],c[N],n;
int f[N][20];
void build_sa(int m){
int i,*x=t,*y=t2;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[i]=s[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(int k=1;k<=n;k<<=1){
int p=0;
for(i=n-k;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=0;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]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n)break;
m=p;
}
}
int rank[N],height[N];
void getHeight(){
int i,j,k=0;
for(i=0;i<n;i++)rank[sa[i]]=i;
for(i=0;i<n;i++){
if(k)k--;
int j=sa[rank[i]-1];
while(s[i+k]==s[j+k])k++;
height[rank[i]]=k;
}
}
void rmq(){
for(int i=1;i<n;i++) f[i][0]=height[i];
for(int j=1;j<20;j++)
for(int i=1;i+(1<<j)-1<n;i++)
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int lcp(int l,int r){
int k=log2(r-l+1);
return min(f[l][k],f[r+1-(1<<k)][k]);
}
void bu(){
for(int i=1;i<n;i++)
update(rt[i],rt[i-1],sa[i]);
}
int work(int l,int r,int k){
int po=rank[l-1];
//cout<<po<<endl;
int L,R,ans=-1; int mxl,mxr;
L=1; R=po; mxl=mxr=po;
while(L<=R){
int mid=(L+R)>>1;
// cout<<L<<" "<<R<<" "<<mid<<" "<<lcp(mid,po)<<endl;
if(lcp(mid,po)>=r-l+1){
R=mid-1;
ans=mid;
}else{
L=mid+1;
}
}
if(ans!=-1)
mxl=ans;
ans=-1;
if(po<n-1){
L=po+1; R=n-1;
while(L<=R){
// cout<<L<<" "<<R<<endl;
int mid=(L+R)>>1;
if(lcp(po+1,mid)>=r-l+1){
L=mid+1;
ans=mid;
}else{
R=mid-1;
}
}
if(ans!=-1)
mxr=ans;
}
// cout<<n<<endl;
// cout<<mxl<<" "<<mxr<<endl;
if(lcp(mxl,mxr)>=r-l+1){
mxl=mxl-1;
}
if(mxr-mxl+1<k) return -1;
return query(rt[mxr],rt[mxl-1],k)+1;
}
}sa;
char s[N];
int main(){
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
int t; scanf("%d",&t);
while(t--){
int n,q; scanf("%d%d",&n,&q);
scanf("%s",s);
nico=0;
for(int i=0;i<n;i++)
sa.s[i]=s[i]-'a'+1;
sa.s[n]=0; sa.n=n+1;
sa.build_sa(27); sa.getHeight();
build(rt[0],0,N);
sa.rmq(); sa.bu();
for(int i=1;i<=q;i++){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",sa.work(l,r,k));
}
}
}

hdu 6704 K-th occurrence(后缀数组+可持久化线段树)的更多相关文章

  1. luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

    luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...

  2. HDU 5558 Alice's Classified Message(后缀数组+二分+rmq(+线段树?))

    题意 大概就是给你一个串,对于每个\(i\),在\([1,i-1]\)中找到一个\(j\),使得\(lcp(i,j)\)最长,若有多个最大\(j\)选最小,求\(j\)和这个\(lcp\)长度 思路 ...

  3. Luogu3732 [HAOI2017] 供给侧改革 【后缀数组】【线段树】【乱搞】

    题目分析: 这道题我是乱搞的,因为他说$01$串是随机的. 那么我们可以猜测能够让LCP变大的地方很少.求出后缀数组之后可能让LCP变大的地方就等价于从大到小往height里动态加点同时维护这个点左右 ...

  4. Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)

    先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...

  5. 【后缀数组】【线段树】poj3974 Palindrome

    考虑奇数长度的回文,对于字符串上的每个位置i,如果知道从i开始的后缀和到i为止的前缀反转后的字符串的lcp长度的话,也就知道了以第i个字符为对称中心的最长回文的长度了.因此,我们用在S中不会出现的字符 ...

  6. Luogu P3919 【模板】可持久化数组 可持久化线段树

    其实就是可持久化线段树的模板题线段树不会看这里 #include<bits/stdc++.h> ; using namespace std; ]; ],rc[N*],val[N*],cnt ...

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

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

  8. hdu 3553 Just a String (后缀数组)

    hdu 3553 Just a String (后缀数组) 题意:很简单,问一个字符串的第k大的子串是谁. 解题思路:后缀数组.先预处理一遍,把能算的都算出来.将后缀按sa排序,假如我们知道答案在那个 ...

  9. 【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位 ...

随机推荐

  1. day119:MoFang:宠物的状态改动&宠物粮道具的使用&宠物死亡处理

    目录 1.宠物的状态改动 2.宠物粮道具的使用 3.宠物死亡处理 1.宠物的状态改动 1.在setting表中为每个宠物配置生命周期时间 因为宠物有多个,每个宠物会有不同的初始生命的饥饿时间,所以我们 ...

  2. thinkphp3.2框架运行原理

    thinkphp3.2是使用率非常普遍的国产php框架,以简单易于上手闻名,那么它框架结构是怎样的? tp3.2设计简单来说就是CBD,core(框架核心文件),bebavior(行为,tp3.2一大 ...

  3. 九:APP及其他资产

    APP提取一键反编译提取 APP抓数据包进行工具配合 各种第三方应用相关探针技术 各种服务器接口相关探针技术 APP提取及抓包及后续配合 某APK一键提取反编译 利用burp历史抓更多URL 某IP无 ...

  4. PC个人隐私保护小方法

    前言 近期爆出了腾讯读取用户浏览器浏览记录的消息.话不过说直接上图,懂的自然懂. 网上也有详细的分析文章,不管它读取后用来做什么,在你不知情的情况下读取了你的浏览器浏览记录,你说气不气. 虽然在整体大 ...

  5. SVM 支持向量机算法-原理篇

    公号:码农充电站pro 主页:https://codeshellme.github.io 本篇来介绍SVM 算法,它的英文全称是 Support Vector Machine,中文翻译为支持向量机. ...

  6. [Poi2012]Rendezvous

    题目描述 给定一个n个顶点的有向图,每个顶点有且仅有一条出边. 对于顶点i,记它的出边为(i, a[i]). 再给出q组询问,每组询问由两个顶点a.b组成,要求输出满足下面条件的x.y: 从顶点a沿着 ...

  7. Py基础—变量名,条件循环,空执行,编码,运算符,字符比较,简化写法

    变量名 只能是字母,数字,下划线.数字不能开头,不要和python内置的东西重复.赋予变量名内容:name1 = "shit" 输出变量名内容 print(name1) 条件语句 ...

  8. spring源码分析之玩转ioc:bean初始化和依赖注入(一)

    最近赶项目,天天加班到十一二点,终于把文档和代码都整完了,接上继续整. 上一篇聊了beanProcess的注册以及对bean的自定义修改和添加,也标志着创建bean的准备工作都做好了,接下来就是开大招 ...

  9. 初审blucms(入坑)

    作为一名初来乍到审计小白,从blueCMS入手再好不过了.通过对入门级的cms进行审计以及一个整体的框架和常见的漏洞学习,对个人而言是一次不错的学习经历.话不多说直接进入主题. 代码审计环境 Blue ...

  10. Maven 知识点总结以及解决jar报冲突的几种方法

    1.常见的命令 Compile Test Package Install Deploy Clean 2.坐标的书写规范 groupId 公司或组织域名的倒序 artifactId 项目名或模块名 ve ...