BZOJ3230 相似子串

给一个串,查询排名i和j的子串longest common suffix和longest common prefix

思路其实还是蛮好想的,就是码起来有点恶心。可以发现后缀拍完序之后的子串可以根据sa自前而后的顺序标子串排名,和统计不同字串那里差不多,自lcp后的是新子串,开始标记排名。实际操作时在每个后缀上标这一后缀开始第一个新子串排名,可证是单调增的,然后查询就二分查出子串开始的后缀也就是位置啦,然后用st表维护子串(所在后缀的)lcp即可。lcs的话就把串反转一下做个排序同理st表维护RMQ。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+,Log=;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline void read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=(x<<)+(x<<)+(c^),c=getchar();f?x-=x:;
}
char s[][N];
int po[N],n,q,a,b,h1,r1,h2,r2,l1,l2;
ll q1,q2; int cnt[][N],h[][N],sa[][N],rk[][N],y[][N],m,p;
inline void suffix_sort(int l){ m=,p=;
for(register int i=;i<=n;++i)++cnt[l][rk[l][i]=s[l][i]];
for(register int i=;i<=m;++i)cnt[l][i]+=cnt[l][i-];
for(register int i=n;i;--i)sa[l][cnt[l][rk[l][i]]--]=i;
for(register int k=;k<n;k<<=,p=){
for(register int i=n-k+;i<=n;++i)y[l][++p]=i;
for(register int i=;i<=n;++i)if(sa[l][i]>k)y[l][++p]=sa[l][i]-k;
for(register int i=;i<=m;++i)cnt[l][i]=;
for(register int i=;i<=n;++i)++cnt[l][rk[l][y[l][i]]];
for(register int i=;i<=m;++i)cnt[l][i]+=cnt[l][i-];
for(register int i=n;i;--i)sa[l][cnt[l][rk[l][y[l][i]]]--]=y[l][i];
swap(rk,y);rk[l][sa[l][]]=p=;
for(register int i=;i<=n;++i)rk[l][sa[l][i]]=y[l][sa[l][i-]]==y[l][sa[l][i]]&&y[l][sa[l][i-]+k]==y[l][sa[l][i]+k]?p:++p;
if(p==n)break;m=p;
}p=;
for(register int i=;i<=n;h[l][rk[l][i]]=p,p?--p:,++i)while(s[l][i+p]==s[l][sa[l][rk[l][i]-]+p]&&++p);
} ll rank[N],tot=;
inline void mark(){for(register int i=;i<=n;++i)rank[i]=tot,tot+=n-sa[][i]+-h[][i];--tot;}
struct st_table{
int lcp[N][Log];
inline void build(int l){
for(register int i=;i<=n;++i)lcp[i][]=h[l][i];
for(register int k=;k<=po[n];++k)for(register int i=;i<=n+-(<<k);++i)
lcp[i][k]=_min(lcp[i][k-],lcp[i+(<<(k-))][k-]);
}
inline int RMQ(int l,int r){return _min(lcp[l][po[r-l+]],lcp[r-(<<po[r-l+])+][po[r-l+]]);}
}pos,neg;//positive,negative int main(){//freopen("tmp.txt","r",stdin);
read(n),read(q),scanf("%s",s[]+);
for(register int i=;i<=n;++i)po[i]=(i-)==(<<(po[i-]+))?po[i-]+:po[i-];
for(register int i=;i<=n;++i)s[][i]=s[][n-i+];
suffix_sort(),suffix_sort(),mark();
pos.build(),neg.build();
// for(register int i=1;i<=n;++i)cerr<<s[1][i];puts("");
// for(register int i=1;i<=n;++i)cerr<<i<<" "<<rk[1][i]<<" "<<sa[1][i]<<endl;
for(register int i=;i<=q;++i){
read(q1),read(q2);
if(q1>tot||q2>tot){printf("-1\n");continue;}
h1=upper_bound(rank+,rank+n+,q1)-rank-,h2=upper_bound(rank+,rank+n+,q2)-rank-;
l1=sa[][h1],l2=sa[][h2],r1=l1+h[][h1]+q1-rank[h1],r2=l2+h[][h2]+q2-rank[h2];
if(h1==h2)a=_min(r1,r2)-l1+;
else{
if(h1>h2)h1^=h2^=h1^=h2;
a=pos.RMQ(h1+,h2);if((a>r1-l1+)||(a>r2-l2+))a=_min(r1-l1+,r2-l2+);
}//get a.
h1=rk[][n-r1+],h2=rk[][n-r2+];//cerr<<l1<<" "<<r1<<" "<<l2<<" "<<r2<<" "<<h1<<" "<<h2<<endl;
if(h1==h2)b=r1-_max(l1,l2)+;
else{
if(h1>h2)h1^=h2^=h1^=h2;
b=neg.RMQ(h1+,h2);if((b>r1-l1+)||(b>r2-l2+))b=_min(r1-l1+,r2-l2+);
}//get b.
printf("%lld\n",1ll*a*a+1ll*b*b);
}
return ;
}

BZOJ3230 相似子串[后缀数组+二分+st表]的更多相关文章

  1. BZOJ 3230 相似子串 | 后缀数组 二分 ST表

    BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...

  2. [BZOJ4310] 跳蚤 - 后缀数组,二分,ST表

    [BZOJ4310] 跳蚤 Description 首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\) ,他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 ...

  3. bzoj 3230 相似子串 —— 后缀数组+二分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...

  4. [BZOJ3230]相似子串(后缀数组)

    显然可以通过后缀数组快速找到询问的两个串分别是什么,然后正反各建一个后缀数组来求两个串的LCP和LCS即可. #include<cstdio> #include<cstring> ...

  5. 【BZOJ3230】相似子串 后缀数组+二分+RMQ

    [BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...

  6. UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)

    连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...

  7. [BZOJ3277/BZOJ3473] 串 - 后缀数组,二分,双指针,ST表,均摊分析

    [BZOJ3277] 串 Description 现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Solution 首先将所有串连 ...

  8. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

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

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

随机推荐

  1. JAVA实现KNN分类

    转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/51064307 http://www.llwjy.com/blogdetail/f ...

  2. Angular 一些问题(跨域,后台接收不到参数)

    1,跨域:跟前端没多大关系的,后台没设置头而已.这时候如果你们后端太菜你可以叫他加上每种语言 都不同,但是里面的呢荣是一样的.具体跨域可以跳转这里http://www.cnblogs.com/dojo ...

  3. request 防盗链

    package request; import java.io.IOException;import javax.servlet.ServletException;import javax.servl ...

  4. 百度富文本编辑器Ueditor上传图片时标签中添加宽高

    ueditor.all.js中:直接搜索callback() function callback(){ try{ var link, json, loader, body = (iframe.cont ...

  5. 【EDAS问题】轻量级EDAS部署hsf服务出现找不到类的解决方案

    本地运行轻量级EDAS调用服务的时候报错如下: 2018-01-08 13:16:58.029 WARN [http-bio-8090-exec-8:t.hsf] [RPC Protocol call ...

  6. iOS中数组遍历的方法及比較

    数组遍历是编码中非经常见的一种需求.我们来扒一拔iOS里面都有什么样的方法来实现,有什么特点. 由于iOS是兼容C语言的.所以C语言里面的最最常见的for循环遍历是没有问题的. 本文中用的数组是获取的 ...

  7. WPF SDK研究 之 数据绑定

    这一章介绍数据绑定.本章共计27个示例,全都在VS2008下.NET3.5测试通过,点击这里下载:ConnectedData.rar 1.ShowDataWithoutBinding注: <?M ...

  8. struts2 Eclipse 中集成strust2开发框架实例

    下面通过建立一个小的实例具体来说明Eclipse 集成struts2,以下实例采用的为 struts2 版本为 struts2 2.2.3.1 为应用. 1. 下载struts2的开发包 第一步: 在 ...

  9. EasyNVR RTSP转HLS(m3u8+ts)流媒体服务器前端构建之:bootstrap-datepicker日历插件的实时动态展现

    EasyNVR中有对录像进行检索回放的功能,且先抛开录像的回放,为了更好的用户体验过.让用户方便快捷的找到对应通道对应日期的录像视频,是必须的功能. 基于上述的需求,为前端添加一个日历插件,在日历上展 ...

  10. Mybatis的配置文件和映射文件详解

    一.Mybatis的全局配置文件 1.SqlMapConfig.xml是mybatis的全局配置文件,配置内容如下: properties(属性) settings(全局配置参数) typeAlias ...