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. Azure Table Storage(一) : 简单介绍

    Azure Table Storage是什么: Azure Table Storage是隶属于微软Azure Storage这个大服务下的一个子服务, 这个服务在Azure上算是老字号了, 个人大概在 ...

  2. Linux 防火墙基于 CentOS7 的防火墙操作命令

    防火墙服务操作命令 重启防火墙 systemctl restart firewalld 查看防火墙状态 systemctl status firewalld 开启.关闭.重启防火墙 # 开启 serv ...

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

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

  4. ASP.NET Core错误处理中间件[2]: 开发者异常页面

    <呈现错误信息>通过几个简单的实例演示了如何呈现一个错误页面,该过程由3个对应的中间件来完成.下面先介绍用来呈现开发者异常页面的DeveloperExceptionPageMiddlewa ...

  5. 【MySQL】ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing

    今天上午遇到了一个问题,新创建的mysql5.7的数据库,由于初始化有点问题,没有给root密码,用了免密码登录. 但是,修改了root密码之后,把配置中的免密登录的配置注释掉后,重启服务.服务正常启 ...

  6. SDUST数据结构 - chap9 排序

    判断题: 选择题: 编程题: 7-1 排序: 输入样例: 11 4 981 10 -17 0 -20 29 50 8 43 -5 输出样例: -20 -17 -5 0 4 8 10 29 43 50 ...

  7. os.walk() 遍历目录下的文件夹和文件

    os.walk(top, topdown=True, onerror=None, followlinks=False) top:顶级目录 os.walk()返回一个三元tupple(dirpath, ...

  8. Zju1100 Mondriaan

    题目描述 有一个m行n列的矩阵,用1*2的骨牌(可横放或竖放)完全覆盖,骨牌不能重叠,有多少种不同的覆盖的方法? 你只需要求出覆盖方法总数mod p的值即可. 输入格式 三个整数数n,m,p,m< ...

  9. IP2726中文规格书

    IP2726_AC_FBR 是一款集成多种协议.用于USB-A 和 TYPE-C 双端口输出的快充协议 IC.支持多种快充协议,包括 USB TypeC DFP,PD2.0/PD3.0/PPS ,HV ...

  10. Docker下梦织CMS的部署

    摘要:Docker的广泛应用相对于传统的虚拟机而言提高了资源的利用率,推广后docker的影响不容忽视,在启动速度.硬盘.内存.运行密度.性能.隔离性和迁移性方面都有很大的提高.本次实训我们在cent ...