bzoj 4556 字符串 —— 后缀数组+主席树
题目: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 字符串 —— 后缀数组+主席树的更多相关文章
- bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...
- [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...
- BZOJ3473:字符串(后缀数组,主席树,二分,ST表)
Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...
- [HEOI2016] 字符串 - 后缀数组,主席树,ST表,二分
[HEOI2016] 字符串 Description 给定一个字符串 \(S\), 有 \(m\) 个询问,每个询问给定参数 \((a,b,c,d)\) ,求 \(s[a..b]\) 的子串与 \(s ...
- BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)
Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...
- P4094 [HEOI2016/TJOI2016]字符串 后缀数组+主席树+二分答案
$ \color{#0066ff}{ 题目描述 }$ 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须 ...
- BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)
题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...
- BZOJ 4556(后缀数组+主席树求前驱后继+二分||后缀数组+二分+可持久化线段树)
换markdown写了.. 题意: 给你一个1e5的字符串,1e5组询问,求\([l_1,r_1]\)的所有子串与\([l_2,r_2]\)的lcp 思路: 首先可以发现答案是具有单调性的,我们考虑二 ...
- BZOJ4556 [Tjoi2016&Heoi2016]字符串 【后缀数组 + 主席树 + 二分 + ST表】
题目 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了 一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职 ...
随机推荐
- skynet 创建存储过程脚本
最近主程更改了数据库的操作方案,由之前的拼写sql脚本转为在mysql端创建好存储过程后,直接调用存储过程. 首先对一个表测试上述过程: 数据库端存储过程:(测试表) CREATE TABLE `ra ...
- 端口被sysmtem占用
今天启动Apache的时候老是提示失败,很简单,使用 netstat -ano 发现80端口被占用.如图所示:
- Tomcat出现java.lang.Exception: Socket bind failed
今天测试系统,Tomcat(apache-tomcat-6.0.20windows版)突然出现异常,导致JSP页面无法运行.错误提示如下:2014-3-12 17:13:29 org.apache.c ...
- MSSQL2008 临时总结文档2014
2. 索引可以建立在基表上(基表索引),也可以视图上称为视图索引. 基表索引是建立在表数据中的,故视图索引是建立在查询后的结果集上的. (假如建立了视图索引)当从视图中取数据的时候,优化查询分析器会 ...
- C++(十九) — const 和 #define 区别
1.const (1)C++对 const 常量的处理过程:当编译器碰到 常量声明 时,在符号表中放入常量,编译时发现使用常量,则直接以符号表中的值替换. (2)如果,编译中发现,对 const 使 ...
- Oracle DBLink连接数过多的问题(Ora-02020)
前不久开发人员编译存储时报ORA -02020 错,如下是解决方案步骤. 报错全信息: Error:OR A -04052在查: 找远程对象 NIP.PB_PERADDRESSLIST@DB_NI ...
- ajax用json实现数据传输
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族 ...
- LeetCode OJ:Compare Version Numbers(比较版本字符串)
Compare two version numbers version1 and version2.If version1 > version2 return 1, if version1 &l ...
- java中商业数据计算时用到的类BigDecimal和DecimalFormat
1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确 ...
- Flask的请求与响应
Flask的请求与响应 1 请求相关信息 request.method # 请求方法 request.args # get 请求的参数 request.form # post请求的参数 request ...