BZOJ3230 相似子串[后缀数组+二分+st表]
给一个串,查询排名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表]的更多相关文章
- BZOJ 3230 相似子串 | 后缀数组 二分 ST表
BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...
- [BZOJ4310] 跳蚤 - 后缀数组,二分,ST表
[BZOJ4310] 跳蚤 Description 首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\) ,他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 ...
- bzoj 3230 相似子串 —— 后缀数组+二分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...
- [BZOJ3230]相似子串(后缀数组)
显然可以通过后缀数组快速找到询问的两个串分别是什么,然后正反各建一个后缀数组来求两个串的LCP和LCS即可. #include<cstdio> #include<cstring> ...
- 【BZOJ3230】相似子串 后缀数组+二分+RMQ
[BZOJ3230]相似子串 Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符串S.接下来Q行,每行两个整数i和j.(1≤i≤j). Output 输出 ...
- UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)
连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...
- [BZOJ3277/BZOJ3473] 串 - 后缀数组,二分,双指针,ST表,均摊分析
[BZOJ3277] 串 Description 现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Solution 首先将所有串连 ...
- BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)
Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
随机推荐
- PX4学习之-uORB简单体验
一.前言 最近项目使用到 CPU2 与 CPU0 之间的通信, 使用定时器传递消息到 CPU0 后, CPU0 需要将消息分发到不同的应用程序里面. PX4 里面使用的是 uORB 多线程/进程通信机 ...
- dede二级导航与二级栏目 ----内容介绍二级导航
{dede:channelartlist typeid='top'}//如果只需要拿一列,则需要使用row='1'这个属性否则会根据子频道的数目循环输出 <a href="{dede: ...
- POJ3009 Curling 2.0(DFS)
迷宫问题求最短路. 略有不同的是假设不碰到石头的话会沿着一个方向一直前进,出界就算输了.碰到石头,前方石头会消失,冰壶停在原地. 把这个当作状态的转移. DFS能够求出其最小操作数. #include ...
- spark on yarn 配置history server
spark在yarn模式下配置history server 1.建立hdfs文件– hadoop fs -mkdir /user/spark– hadoop fs -mkdir /user/spark ...
- K均值算法总结
这几天在一个项目上需要用到K均值聚类算法,以前都是直接利用百度老师copy一个Kmeans算法代码,这次想自己利用已知的算法思想编写一下,编写才知道,虽然熟悉了算法思想,真正实现时,还是遇到不少bug ...
- 安装Redis图形监控工具---RedisLive
RedisLive简介 RedisLive是一款用Python编写基于WEB的Redis图形监控工具,也是一款实时监控Redis数据的开源软件,以WEB的形式展现出redis中的key的情况,实例数据 ...
- 苹果开发之COCOA编程(第三版)下半部分
第十八章:Image和鼠标事件 1.NSResponderNSView继承自NSResponder类.所有的事件处理方法都定义在NSResponder类中.NSResponder申明了如下方法:- ( ...
- 【BZOJ4373】算术天才⑨与等差数列 线段树+set
[BZOJ4373]算术天才⑨与等差数列 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k, ...
- nexus搭建maven私服及私服jar包上传和下载
nexus搭建maven私服及私服jar包上传和下载 标签: nexus管理maven库snapshot 2017-06-28 13:02 844人阅读 评论(0) 收藏 举报 分类: Maven(1 ...
- 使用active mq
1 windows下使用active mq 1.1 下载active mq 1.2 点击根目录\bin\win64\activemq.bat运行 1.3 登陆查看 http://localhost:8 ...