hdu 6704 K-th occurrence(后缀数组+可持久化线段树)
Problem Description
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 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
If such position don't exists, output −1 instead.
Sample Input
Sample Output
思路:
我们要找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(后缀数组+可持久化线段树)的更多相关文章
- luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)
luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...
- HDU 5558 Alice's Classified Message(后缀数组+二分+rmq(+线段树?))
题意 大概就是给你一个串,对于每个\(i\),在\([1,i-1]\)中找到一个\(j\),使得\(lcp(i,j)\)最长,若有多个最大\(j\)选最小,求\(j\)和这个\(lcp\)长度 思路 ...
- Luogu3732 [HAOI2017] 供给侧改革 【后缀数组】【线段树】【乱搞】
题目分析: 这道题我是乱搞的,因为他说$01$串是随机的. 那么我们可以猜测能够让LCP变大的地方很少.求出后缀数组之后可能让LCP变大的地方就等价于从大到小往height里动态加点同时维护这个点左右 ...
- Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)
先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...
- 【后缀数组】【线段树】poj3974 Palindrome
考虑奇数长度的回文,对于字符串上的每个位置i,如果知道从i开始的后缀和到i为止的前缀反转后的字符串的lcp长度的话,也就知道了以第i个字符为对称中心的最长回文的长度了.因此,我们用在S中不会出现的字符 ...
- Luogu P3919 【模板】可持久化数组 可持久化线段树
其实就是可持久化线段树的模板题线段树不会看这里 #include<bits/stdc++.h> ; using namespace std; ]; ],rc[N*],val[N*],cnt ...
- HDU - 6704 K-th occurrence (后缀数组+主席树/后缀自动机+线段树合并+倍增)
题意:给你一个长度为n的字符串和m组询问,每组询问给出l,r,k,求s[l,r]的第k次出现的左端点. 解法一: 求出后缀数组,按照排名建主席树,对于每组询问二分或倍增找出主席树上所对应的的左右端点, ...
- hdu 3553 Just a String (后缀数组)
hdu 3553 Just a String (后缀数组) 题意:很简单,问一个字符串的第k大的子串是谁. 解题思路:后缀数组.先预处理一遍,把能算的都算出来.将后缀按sa排序,假如我们知道答案在那个 ...
- 【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询
Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位 ...
随机推荐
- PHP 获取天气
/** * 获取天气 */ function get_tq () { //获取用户ip地址 $ip = get_real_ip(); // $ip = '123.125.71.38'; //根据ip地 ...
- (解决)easypoi图片导出只占用一个单元格
@ 目录 前提 依赖环境 问题原因 解决方案 重写jar中的方法 原理 前提 本解决方案来源于网络,因解决自己需求,因此自行记录起来,如有侵权请联系我. 依赖环境 easypoi--依赖版本3.1.0 ...
- LeetCode682 棒球比赛
题目描述: 你现在是棒球比赛记录员.给定一个字符串列表,每个字符串可以是以下四种类型之一:1.整数(一轮的得分):直接表示您在本轮中获得的积分数.2. "+"(一轮的得分):表示本 ...
- (二)数据源处理3-python处理包含合并单元格的excel
分析:
- mac安装Navicat Premium Mac 12 破解版
参考:https://www.cnblogs.com/lyfstorm/p/11123159.html 激活后:
- TCP/IP协议栈在Linux内核中的运行时序分析
网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...
- MySQL select 查询之分组和过滤
SELECT 语法 SELECT [ALL | DISTINCT] {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][ ...
- Pycharm同时执行多个脚本文件
Pycharm同时执行多个脚本文件 设置Pycharm使它可以同时执行多个程序 打开Pycharm 找到Run,点击确认 点击Edit Configurations 右上角Allow parallel ...
- 【Linux】大于2T的磁盘怎么分区?
环境CentOS7.1 2.9t磁盘 fdisk 只能分区小于2t的磁盘,大于2t的话,就要用到parted 1,将磁盘上原有的分区删除掉: 进入:#parted /dev/sdb 查看:(par ...
- ctfhub技能树—信息泄露—备份文件下载—vim缓存
打开靶机 查看页面信息 在使用vim时会创建临时缓存文件,关闭vim时缓存文件则会被删除,当vim异常退出后,因为未处理缓存文件,导致可以通过缓存文件恢复原始文件内容 以 index.php 为例:第 ...