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个问题,才能打开箱子拿到礼物,升职 ...
随机推荐
- SQL编码规范
1 目的 为了保证所每个项目组编写出的程序都符合相同的规范,便于理解和维护,便于检查.减少出错概率,有助于成员间交流,保证一致性.统一性而建立的SQL程序编码规范. 2 范 ...
- 数字组合问题:Combination,CombinationSum,CombinationSum2,CombinationSum3
Combination问题描述:给定n和k,找出1-n之间所有k个数的组合,例如:n=3,k=2,返回 [[1,2] [1,3] [2,3]] 算法分析:利用递归.递归边界就是curr.size( ...
- try中的return语句,在finally前执行还是在finally后执行?
try中有的return语句,也有finally语句,请问finally是否执行,如果执行的话finally在return前执行还是在return后执行? 答案:finally的内容会执行,并且在re ...
- ECS vs. Kubernetes 类似而又不同
C2Container Service (ECS)和Kubernetes (K8s) 都解决了同样的问题:跨越主机集群管理容器.ECS和Kubernetes之间的斗争让我想起了vi和Emacs之间的编 ...
- tensorflow笔记:使用tf来实现word2vec
(一) tensorflow笔记:流程,概念和简单代码注释 (二) tensorflow笔记:多层CNN代码分析 (三) tensorflow笔记:多层LSTM代码分析 (四) tensorflow笔 ...
- redis key 通配符 查询相应的key
keys pattern 查询相应的key 在redis里,允许模糊查询key 有3个通配符 *, ? ,[] *: 通配任意多个字符 ?: 通配单个字符 []: 通配括号内的某1个字符 redis ...
- No mojo definitions
pom.xml <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</gro ...
- idea的常用设置
1.官网 官网:http://www.jetbrains.com/idea/download/#section=windows 官方文档:http://www.jetbrains.com/help/i ...
- mongodb之一些简单的增删改查语句
数据库操作:show dbs;#查看数据库use test;#如果没有就创建一个db;#查看当前数据库db.dropDatabase();#删除数据库 数据操作:show collections:#查 ...
- 【枚举】【最小生成树】【kruscal】bzoj3754 Tree之最小方差树
发现,若使方差最小,则使Σ(wi-平均数)2最小即可. 因为权值的范围很小,所以我们可以枚举这个平均数,每次把边权赋成(wi-平均数)2,做kruscal. 但是,我们怎么知道枚举出来的平均数是不是恰 ...