大意: 给定串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);
}
}
}

K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)的更多相关文章

  1. HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...

  2. [CSP-S模拟测试]:platform(后缀数组+二分+线段树)

    题目传送门 题目描述 走过奈何桥有一个名叫望乡台的土台,望乡台有个名曰孟婆的老妇人在卖孟婆汤.一生爱恨情仇,一世浮沉得失,都可以随这碗孟婆汤遗忘得干干净净.现在有$n$碗孟婆汤摆成一排,汤的品种不超过 ...

  3. HDU 5558 后缀数组+二分

    题意有一些绕,但其实就是对于不断变化的i,求以j(0=j<i)使得suffix[j]与suffix[i]的最长公共前缀最长,如果有多个j,则取最小的j. 可以在rank数组中二分,在1-rank ...

  4. UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)

    题解: 题意: 输入n个DNA序列,你的任务是求出一个长度最大的字符串,使得它在超过一半的DNA序列中出现.如果有多解,按照字典序从小到大输入所有解. 把n个DNA序列拼在一起,中间用没有出现过的字符 ...

  5. BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

  6. hdu 3948 后缀数组

    The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (J ...

  7. 【bzoj4310】跳蚤 后缀数组+二分

    题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...

  8. BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)

    题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...

  9. POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)

    洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...

随机推荐

  1. 获取客户机MAC地址 根据IP地址 获取机器的MAC地址 / 获取真实Ip地址

    [DllImport("Iphlpapi.dll")] private static extern int SendARP(Int32 dest, Int32 host, ref ...

  2. win10无法开启网络发现怎么办 如何启用网络发现

    鼠标右键点击桌面左下角的开始按钮,在弹出的菜单中选择“运行”菜单项.   在打开的Windows10运行窗口中,输入Services.msc,然后点击确定按钮.   在打开的Windows10服务窗口 ...

  3. 使用 VS Code 搭建 TypeScript 开发环境

    使用 VS Code 搭建 TypeScript 开发环境 TypeScript 是 JavaScript 的超集,TypeScript 只是增强了 JavaScript 而非改变了 JavaScri ...

  4. C#设计模式:备忘录模式(Memento Pattern)

    一,C#设计模式:备忘录模式(Memento Pattern) 1.发起人角色(Originator):记录当前时刻的内部状态,负责创建和恢复备忘录数据.负责创建一个备忘录Memento,用以记录当前 ...

  5. mysql proxysql的简单部署读写分离

    环境需求(centos) proxysql-server(1)-- 地址:proxysql-service mysql-master-server(1)--- 地址:mysql1-service my ...

  6. rev 反向输出文件内容

    1.命令功能 rev 按行反向输出文件内容 2.语法格式 rev  file 3.使用范例 [root@localhost ~]# echo {a..k} >> test [root@lo ...

  7. activity manager

    首先 activity manager 作为一个独立的服务存在,所有系统中的所有 app 的 activity 都通过这个 service 来管理 同时 activity manager 维护着多个 ...

  8. VS2017报错:未提供初始值设定项

    今天在使用VS2017写程序时,报错: 出错的代码如下: #include "pch.h" #include <iostream> #include <threa ...

  9. LOJ bitset+分块 大内存毒瘤题

    题面 $ solution: $ 真的没有想到可以用分块. 但是可以发现一个性质,每个询问只关心这个点最后一次赋值操作,和这个赋值操作后的所有取 $ min $ 操作.这个感觉很有用,但是真的很难让人 ...

  10. 【LOJ#6036】[雅礼集训2017Day4]编码

    传送门 题意简述 判定 n 个含 ? 字符的二进制串是否存在一种把 0/1 填入 ? 中的方案使得任意两个串不具有前缀关系. (一个串最多一个 ?) Sol 二进制串 ,并且一个串最多一个 '?' 很 ...