大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置.

这是一篇很好的题解:

https://blog.csdn.net/sdauguanweihong/article/details/100063096

加点个人:

我对上面的题解更为详细的解释下:

后缀数组处理出来的heigth[] 数组 有个这样的性质:

对于排名 a 的后缀字符串 与排名 b 的后缀字符串  ,他们的最长公共前缀的长度为 min{heigth[a+1],heigth[a+2],heigth[b]};

依据这样的性质就可以二分线段树出[l,r] 这个字符串 是在多少排名的区间[L,R]了;

注意:我本想贪图方便用先二分l然后判断[l,pos] 的最小值复杂度为log*log  这个会T的

所以找这个区间要用log的方法,就是在存了最小值的线段树里面去搜左孩子啊右孩子什么的

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = ;
char s[maxn];
int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],wt[];
int n,k,q; int get_SA(int m){
for(int i= ; i<=m ; i++) c[i]=;
for(int i= ; i<=n ; i++) sa[i]=;
for(int i= ; i<=n ; i++) ++c[x[i]=s[i]];
for(int i= ; i<=m ; i++) c[i]+=c[i-];
for(int i=n ; i>= ; i--) sa[c[x[i]]--]=i;
for(int k= ; k<=n ; k<<=){
int num=;
for(int i=n-k+ ; i<=n ; i++) y[++num]=i;
for(int i= ; i<=n ; i++) if(sa[i]>k) y[++num]=sa[i]-k;
for(int i= ; i<=m ; i++) c[i]=;
for(int i= ; i<=n ; i++) ++c[x[i]];
for(int i= ; i<=m ; i++) c[i]+=c[i-];
for(int i=n ; i>= ; i--) sa[c[x[y[i]]]--]=y[i],y[i]=;
swap(x,y);
x[sa[]]=;
num=;
for(int i= ; i<=n ; i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-]] && y[sa[i]+k]==y[sa[i-]+k]) ? num : ++num;
if (num==n) break;
m=num;
}
}
int get_height() {
int k=;
for (int i=; i<=n; ++i) rk[sa[i]]=i;
for (int i=; i<=n; ++i) {
if (rk[i]==) continue;
if (k) --k;
int j=sa[rk[i]-];
while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
height[rk[i]]=k;
}
} int mi[maxn<<];
void pushup(int rt){
mi[rt]=min(mi[rt<<],mi[rt<<|]);
}
void build(int l,int r,int rt)
{
if ( l==r )
{
mi[rt]=height[l];
return ;
}
int m = (l+r) >> ;
build(l,m,rt<<);
build(m+,r,rt<<|);
pushup(rt);
} int solvel(int o , int l , int r , int x , int v){
int mid=(l+r)>>;
if(r<=x){
if(l==r) return mi[o]>=v?l:-;
if(mi[o<<|]<v) return solvel(o<<|,mid+,r,x,v);
int t=solvel(o<<,l,mid,x,v);
return t==-?mid+:t;
}
if(mid>=x) return solvel(o<<,l,mid,x,v);
int R=solvel(o<<|,mid+,r,x,v);
if (R==-||R>mid+) return R;
int L = solvel(o<<,l,mid,x,v);
return L==-?R:L;
} int solver(int o, int l, int r, int x, int v){
int mid=(l+r)>>;
if (x<=l) {
if (l==r) return mi[o]>=v?l:-;
if (mi[o<<]<v) return solver(o<<,l,mid,x,v);
int t = solver(o<<|,mid+,r,x,v);
return t==-?mid:t;
}
if (mid<x) return solver(o<<|,mid+,r,x,v);
int L = solver(o<<,l,mid,x,v);
if (L==-||L<mid) return L;
int R = solver(o<<|,mid+,r,x,v);
return R==-?L:R;
} int tot;
int lson[maxn<<],rson[maxn<<],T[maxn],cc[maxn<<];
void zhu_build(int &root,int l,int r)
{
root=++tot;
if ( l==r ) return;
int mid=(l+r)/;
zhu_build(lson[root],l,mid);
zhu_build(rson[root],mid+,r);
}
void update(int root,int &rt,int p,int val,int l,int r)
{
rt=++tot;
lson[rt]=lson[root],rson[rt]=rson[root];
cc[rt]=cc[root]+val;
if ( l==r ) return;
int mid=(l+r)/;
if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid);
else update(rson[rt],rson[rt],p,val,mid+,r);
}
int query(int rt_,int rt,int l,int r,int k)
{
if ( l==r ) return l;
int mid=(l+r)/;
int sum=cc[lson[rt_]]-cc[lson[rt]];
if ( sum>=k ) return query(lson[rt_],lson[rt],l,mid,k);
else return query(rson[rt_],rson[rt],mid+,r,k-sum);
} int main(){
int _;scanf("%d",&_);
while(_--){
scanf("%d%d%s",&n,&q,s+); get_SA(); get_height();
build(,n,);
tot=;
zhu_build(T[],,n);
for(int i= ; i<=n ; i++){
update(T[i-],T[i],sa[i],,,n); }
while(q--){
int l,r;scanf("%d%d%d",&l,&r,&k);
int p=rk[l];
int ql = p>?solvel(,,n,p,r-l+)-:;
int qr = p<n?solver(,,n,p+,r-l+):n;
if (ql<) ql = p;
if (qr<) qr = p;
int ans;
if(qr-ql+<k)
ans=-;
else
ans=query(T[qr],T[ql-],,n,k); printf("%d\n",ans);
}
}
}

最新文章

  1. oracle查询以当前年份为准的近些年数据
  2. jQuery的常见操作
  3. [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)
  4. 9个 SSH常用命令选项
  5. JS获取节点方法
  6. Spring boot 默认静态资源路径与手动配置访问路径
  7. mysql5.7.16二进制安装
  8. Java 解压zip压缩包
  9. pymongo 一篇文章搞定
  10. keras 的 Deeplabv3+ 实现遇到的问题
  11. Ultimate Guide to WhatsApp for Business 2019
  12. Java使用算数运算符实现两个整数互换
  13. 如何打开用eclipse没有.project文件的Java工程
  14. Linux&#160;Linux下最大文件描述符设置
  15. 浅谈MySQL引擎(纯个人理解,如有错误请指正)
  16. vue运行报错--dependency
  17. mvn 修改所有子项目pom版本
  18. 11.纯 CSS 创作一个荧光脉冲 loader 特效
  19. java使用jdom生成xml格式文件
  20. linux查看是否有某个运行的进程命令

热门文章

  1. 关于E980
  2. PostgreSQL设计之初的大量论文
  3. layui动态渲染select等组件并初始化赋值失败
  4. 【Python】循环结构中的else
  5. [LeetCode] 103. 二叉树的锯齿形层次遍历
  6. Node.js+webSocket
  7. ASP.net解析JSON
  8. gulp程序怎么跑起来 及 使用中遇到的常见错误
  9. Python multiprocessing使用详解
  10. /etc/nscd.conf - 域名服务缓存守护进程配置文件