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个问题,才能打开箱子拿到礼物,升职 ...
随机推荐
- AtCoder Regular Contest 093
AtCoder Regular Contest 093 C - Traveling Plan 题意: 给定n个点,求出删去i号点时,按顺序从起点到一号点走到n号点最后回到起点所走的路程是多少. \(n ...
- eclipse中去掉警告提示
有时候我们要去掉这些不必要的提示 下面我们来设置去掉这些警告提示
- linux下gzip压缩同样内容大小不一样
一份数据,两种传输方式进行收集. 一份数据:有多台数据采集节点或者多个数据源 两种方式:一种是从依次多个采集节点或者多个数据源将数据拷贝过来,合并为一个文件 另外一种是多个采集节点或者数据源同时向汇总 ...
- NumPy排序、搜索和计数函数
NumPy - 排序.搜索和计数函数 NumPy中提供了各种排序相关功能. 这些排序函数实现不同的排序算法,每个排序算法的特征在于执行速度,最坏情况性能,所需的工作空间和算法的稳定性. 下表显示了三种 ...
- echarts的散点图
目前页面中有一个故障数据,做成散点图的效果,打算用echarts 来实现,国内的图表类其实选择挺多的,个人觉得echarts是比较好用的,来看看它有什么优点,一时中文的,联合百度地图,很多都对国内很友 ...
- Spring MVC + Java 多文件上传及多文件中转上传
1.html内容 <div> <form method="post" action="/Cyberspace/main/informationBatch ...
- 【spark】示例:求Top值
我们有这样的两个文件 第一个数字为行号,后边为三列数据.我们来求第二列数据的Top(N) (1)我们先读取数据,创建Rdd (2)过滤数据,取第二列数据. 我们用filter()来过滤数据 line. ...
- ubuntu下安装交叉编译工具链
/usr/localmkdir arm 将文件file1复制成文件file2 cp file1 file2 /cp /mnt/hgfs/UbuntuGX/arm-2008q3-linux.tar.gz ...
- Android性能调优实例
本文主要分享自己在appstore项目中的性能调优点,包括同步改异步.缓存.Layout优化.数据库优化.算法优化.延迟执行等. 目前性能优化专题已完成以下部分: 性能优化总纲——性能问题及性能调优方 ...
- UI- UINavigationController UITabBarController 使用总结
#pragma mark - UINavigationController UITabBarController ====================================== 控制器 ...