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. npm常用命令(转)

    npm install <name>安装nodejs的依赖包 例如npm install express 就会默认安装express的最新版本,也可以通过在后面加版本号的方式安装指定版本, ...

  2. Spring学习八----------Bean的配置之Resources

    © 版权声明:本文为博主原创文章,转载请注明出处 Resources 针对于资源文件的统一接口 -UrlResource:URL对应的资源,根据一个URL地址即可创建 -ClassPathResour ...

  3. 《JavaScript》——DOM

    DOM (Document Object Model) 即文档对象模型, 针对 HTML 和 XML 文档的 API (应用程序接口) .DOM 描绘了一个层次化的节点树,执行开发者加入.移除和改动页 ...

  4. Bootstrp--一个导航面板切换的实用例子

    <!--导航区开始--> <ul class="nav nav-tabs nav-stacked" role="tablist"> &l ...

  5. 也谈SQL Server 2008 处理隐式数据类型转换在运行计划中的增强 (续)

    在上一篇文章也谈SQL Server 2008 处理隐式数据类型转换在运行计划中的增强中,我提到了隐式数据类型转换添加对于数据分布非常不平均的表.评估的数据行数与实际值有非常大出入的问题,进一步測试之 ...

  6. 原创 | 我被面试官给虐懵了,竟然是因为我不懂Spring中的@Configuration

    GitHub 3.7k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 3.7k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 3.7k Star 的 ...

  7. ss请cc来家里钓鱼,鱼塘可划分为n*m的格子,每个格子有不同的概率钓上鱼,cc一直在坐标(x,y)的格子钓鱼,而ss每分钟随机钓一个格子。问t分钟后他们谁至少钓到一条鱼的概率大?为多少?

    include "stdafx.h" #include<iostream> #include<vector> #include<math.h> ...

  8. linux SPI驱动——spi协议(一)

    一:SPI简介以及应用 SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在 ...

  9. PS CC 破解安装教程(亲测可用)

    PS CC版本新增了一些更高效的切图工具,比如可以直接右击图层转化为PNG图像 下面介绍一种亲测可用的破解安装教程 软件下载地址:https://pan.baidu.com/s/1dFJFqhj 一. ...

  10. Mac 常用属性

    如果需要让隐藏的文件可见. 具体做法就是打开一个Terminal终端窗口,输入以下命令: 对于OS X Mavericks 10.9: defaults write com.apple.finder ...