题目: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. Spring_使用 JdbcTemplate和JdbcDaoSupport

  2. DataStage系列教程 (Pivot_Enterprise 行列转换)

    有人提到Pivot_Enterprise这个组件,之前没有用过,今天捣腾了会,写下来供以后参考,如果有什么不对的,还请多指出,谢谢! Pivot_Enterprise主要用来进行行列转换. 1 示例 ...

  3. mapreduce&GFS&bigtable learning

    之前在学习udf的时候接触到了mapreduce,感觉很酷,于是学习了一下,看了mapreduce和GFS的论文,但是没有总结,只是看了一遍 准备利用在学校的时间,学习一下bigtable,然后再认真 ...

  4. Hibernate -- 一对多的双向关联关系

    示例代码: Customer.java package cn.itcast.many2onedouble; import java.util.HashSet; import java.util.Set ...

  5. Rancher+K8S部署手册

    目前创建K8S集群的安装程序最受欢迎的有Kops,Kubespray,kubeadm,rancher,以及个人提供的脚本集等. Kops和Kubespary在国外用的比较多,没有处理中国的网络问题,没 ...

  6. 使用mybatis报错constructor found in com.atguigu.mybatis.bean.Department matching [java.lang.Integer, java.lang.String]

    报错constructor found in com.atguigu.mybatis.bean.Department matching [java.lang.Integer, java.lang.St ...

  7. spring3: Bean的作用域

    3.4  Bean的作用域 什么是作用域呢?即“scope”,在面向对象程序设计中一般指对象或变量之间的可见范围.而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围. ...

  8. KindEditor 上传文件

    Jsp页面代码: <script> var editor; KindEditor.ready(function(K) { editor = K.create('textarea[name= ...

  9. 最大流EK算法/DINIC算法学习

    之前一直觉得很难,没学过网络流,毕竟是基础知识现在重新来看. 定义一下网络流问题,就是在一幅有向图中,每条边有两个属性,一个是cap表示容量,一个是flow 表示流过的流量.我们要求解的问题就是从S点 ...

  10. poi设置背景色

    headStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);    headStyle.setFillForegroundColor(HSSFCo ...