题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556

就是找一个 rk 在一段区间内的前驱和后继;

由于 LCP 还有区间长度的限制,所以可以先二分答案!

然后直接建立 rk 的主席树,查询即可。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return f?ret:-ret;
}
int Min(int x,int y){return x<y?x:y;}
int Max(int x,int y){return x>y?x:y;}
int const xn=1e5+,xm=1e5*;
int n,m,rk[xn],tp[xn],sa[xn],tax[xn],ht[xn][],bin[],bit[xn];
int cnt,rt[xn],ls[xm],rs[xm],sum[xm];
char s[xn];
void rsort()
{
for(int i=;i<=m;i++)tax[i]=;
for(int i=;i<=n;i++)tax[rk[tp[i]]]++;
for(int i=;i<=m;i++)tax[i]+=tax[i-];
for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
}
void init()
{
for(int i=;i<=n;i++)tp[i]=i,rk[i]=s[i];
m=; rsort();
for(int k=;k<=n;k<<=)
{
int num=;
for(int i=n-k+;i<=n;i++)tp[++num]=i;
for(int i=;i<=n;i++)
if(sa[i]>k)tp[++num]=sa[i]-k;
rsort(); swap(rk,tp);
rk[sa[]]=; num=;
for(int i=;i<=n;i++)
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[sa[i]+k]==tp[sa[i-]+k])?num:++num;
if(num==n)break;
m=num;
}
}
void geth()
{
int k=;
for(int i=;i<=n;i++)
{
if(rk[i]==)continue;//continue
if(k)k--; int j=sa[rk[i]-];
while(s[i+k]==s[j+k]&&i+k<=n&&j+k<=n)k++;
ht[rk[i]][]=k;
}
bin[]=; for(int i=;i<;i++)bin[i]=(bin[i-]<<);
bit[]=; for(int i=;i<=n;i++)bit[i]=bit[i>>]+;
for(int i=;i<;i++)
for(int j=;j<=n&&j+bin[i]-<=n;j++)
ht[j][i]=Min(ht[j][i-],ht[j+bin[i-]][i-]);
}
int getlcp(int x,int y)//rk
{
if(x==y)return n-sa[x]+;
if(x>y)swap(x,y); x++;
int r=bit[y-x+];
return Min(ht[x][r],ht[y-bin[r]+][r]);
}
void build(int &x,int y,int l,int r,int v)
{
x=++cnt; ls[x]=ls[y]; rs[x]=rs[y]; sum[x]=sum[y]+;
if(l==r)return;
if(v<=mid)build(ls[x],ls[y],l,mid,v);
else build(rs[x],rs[y],mid+,r,v);
}
int findl(int x,int y,int l,int r)
{
if(!(sum[x]-sum[y]))return -;
if(l==r)return l;
if(sum[ls[x]]-sum[ls[y]])return findl(ls[x],ls[y],l,mid);
return findl(rs[x],rs[y],mid+,r);
}
int findr(int x,int y,int l,int r)
{
if(!(sum[x]-sum[y]))return -;
if(l==r)return l;
if(sum[rs[x]]-sum[rs[y]])return findr(rs[x],rs[y],mid+,r);
return findr(ls[x],ls[y],l,mid);
}
int queryp(int x,int y,int l,int r,int v)
{
if(!(sum[x]-sum[y]))return -;
if(l==r)return l;
if(v<=mid)return queryp(ls[x],ls[y],l,mid,v);
else
{
int tmp=queryp(rs[x],rs[y],mid+,r,v);
if(tmp!=-)return tmp;
return findr(ls[x],ls[y],l,mid);
}
}
int querys(int x,int y,int l,int r,int v)
{
if(!(sum[x]-sum[y]))return -;
if(l==r)return l;
if(v>mid)return querys(rs[x],rs[y],mid+,r,v);
else
{
int tmp=querys(ls[x],ls[y],l,mid,v);
if(tmp!=-)return tmp;
return findl(rs[x],rs[y],mid+,r);
}
}
bool ck(int a,int b,int x,int v)
{
int L=a,R=b-x+;
int pr=queryp(rt[R],rt[L-],,n,v),sc=querys(rt[R],rt[L-],,n,v);
int len=;
if(pr!=-)len=Max(len,getlcp(pr,v));
if(sc!=-)len=Max(len,getlcp(sc,v));
return len>=x;
}
int main()
{
n=rd(); int Q=rd();
scanf("%s",s+); init(); geth();
for(int i=;i<=n;i++)build(rt[i],rt[i-],,n,rk[i]);
for(int i=,a,b,c,d;i<=Q;i++)
{
a=rd(); b=rd(); c=rd(); d=rd();
int l=,r=Min(b-a+,d-c+),res;
while(l<=r)
{
if(ck(a,b,mid,rk[c]))res=mid,l=mid+;
else r=mid-;
}
printf("%d\n",res);
}
return ;
}

bzoj 4556 字符串 —— 后缀数组+主席树的更多相关文章

  1. bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...

  2. [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...

  3. BZOJ3473:字符串(后缀数组,主席树,二分,ST表)

    Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...

  4. [HEOI2016] 字符串 - 后缀数组,主席树,ST表,二分

    [HEOI2016] 字符串 Description 给定一个字符串 \(S\), 有 \(m\) 个询问,每个询问给定参数 \((a,b,c,d)\) ,求 \(s[a..b]\) 的子串与 \(s ...

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

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

  6. P4094 [HEOI2016/TJOI2016]字符串 后缀数组+主席树+二分答案

    $ \color{#0066ff}{ 题目描述 }$ 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须 ...

  7. BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)

    题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...

  8. BZOJ 4556(后缀数组+主席树求前驱后继+二分||后缀数组+二分+可持久化线段树)

    换markdown写了.. 题意: 给你一个1e5的字符串,1e5组询问,求\([l_1,r_1]\)的所有子串与\([l_2,r_2]\)的lcp 思路: 首先可以发现答案是具有单调性的,我们考虑二 ...

  9. BZOJ4556 [Tjoi2016&Heoi2016]字符串 【后缀数组 + 主席树 + 二分 + ST表】

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

随机推荐

  1. SpringBoot MockMVC

    使用MockMvc,我们可以完成基于RESTful风格的SpringMVC的测试,我们可以测试完整的Spring MVC流程,即从URL请求到控制器处理,再到视图渲染都可以测试. @RunWith(S ...

  2. 初入Spring-boot(一)

    一.利用eclipse快速创建Spring-boot项目 1.首先去http://start.spring.io网站,勾选所需要的starter,如图: 选择完之后下载该文件,打开后发现是一个正常的m ...

  3. eclipse设置控制台字体大小

    步骤如下

  4. java类敏感词过滤类

    package com.fpx.pcs.prealert.process.service.impl; import java.util.HashMap;import java.util.HashSet ...

  5. apue.3e源码下载及编译

    下载地址:http://www.apuebook.com/code3e.html 编译方法:http://blog.sina.com.cn/s/blog_94977c890102vdms.html

  6. 缓存技术内部交流_01_Ehcache3简介

    参考资料: http://www.ehcache.org/documentation/3.2/getting-started.html http://www.ehcache.org/documenta ...

  7. Netty(RPC高性能之道)原理剖析

    1,Netty简述 Netty 是一个基于 JAVA NIO 类库的异步通信框架,用于创建异步非阻塞.基于事件驱动.高性能.高可靠性和高可定制性的网络客户端和服务器端 RPC高性能分析,请参考文章“[ ...

  8. srs部署到ubuntu 18.04 server

    srs.txt ubuntu 18.04 安装 srs 1. 上传srs_40.7z和h2ws.7z到linux服务器,然后远程ssh连接 (假设登陆用户名是bob,linux服务器ip是192.16 ...

  9. Linux CentOS服务启动

    Linux CentOS下如何确认MySQL服务已经启动   Linux CentOS一般做为服务器使用,因此,MySQL服务应该随开机自动启动的.正常情况下,查看开机自动启动的服务使用chkconf ...

  10. [转载]JAVA获取word表格中数据的方案

    上一个项目的开发中需要实现从word中读取表格数据的功能,在JAVA社区搜索了很多资料,终于找到了两个相对最佳的方案,因为也得到了不少网友们的帮助,所以不敢独自享用,在此做一个分享. 两个方案分别是: ...