bzoj 2865 字符串识别 —— 后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865
唯一出现的子串就是每个后缀除去和别的后缀最长的 LCP 之外的前缀;
所以用这个更新一段区间的答案,可以用线段树维护;
在 sa[i] ~ sa[i]+LCP+1 位置的答案由 LCP+1 更新,sa[i]+LCP+1 之后的位置就更新一个位置 ps 表示从 ps 到本位置的子串也可以;
最后两个取min即可;
注意如果整个后缀就是 LCP,那么就不能更新了;
线段树中 ps 的初值是0,取答案时注意判掉0。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
int const xn=5e5+,xm=(xn<<);
int n,m,rk[xn],sa[xn],tax[xn],tp[xn],ht[xn];
int cnt=,ls[xm],rs[xm],len[xm],ps[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 work()
{
for(int i=;i<=n;i++)rk[i]=s[i],tp[i]=i;
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(); memcpy(tp,rk,sizeof rk);
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 get()
{
int k=;
for(int i=;i<=n;i++)
{
if(rk[i]==)continue;
if(k)k--; int j=sa[rk[i]-];
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
ht[rk[i]]=k;
}
}
void build(int x,int l,int r)
{
len[x]=n+;
if(l==r)return;
ls[x]=++cnt; build(ls[x],l,mid);
rs[x]=++cnt; build(rs[x],mid+,r);
}
void update(int x,int l,int r,int L,int R,int v)
{
if(l>=L&&r<=R){len[x]=min(len[x],v); return;}
if(mid>=L)update(ls[x],l,mid,L,R,v);
if(mid<R)update(rs[x],mid+,r,L,R,v);
}
void chg(int x,int l,int r,int L,int R,int v)
{
if(l>=L&&r<=R){ps[x]=max(ps[x],v); return;}
if(mid>=L)chg(ls[x],l,mid,L,R,v);
if(mid<R)chg(rs[x],mid+,r,L,R,v);
}
int query(int x,int l,int r,int pos,int v)
{
v=min(v,len[x]);
if(l==r)return v;
if(pos<=mid)return query(ls[x],l,mid,pos,v);
else return query(rs[x],mid+,r,pos,v);
}
int ask(int x,int l,int r,int pos,int v)
{
v=max(v,ps[x]);
if(l==r)return v;
if(pos<=mid)return ask(ls[x],l,mid,pos,v);
else return ask(rs[x],mid+,r,pos,v);
}
int main()
{
scanf("%s",s+); n=strlen(s+); m=;
work(); get(); build(,,n);
for(int i=;i<=n;i++)
{
int lcp=max(ht[i],ht[i+]);
if(sa[i]+lcp<=n)update(,,n,sa[i],sa[i]+lcp,lcp+);//
if(sa[i]+lcp+<=n)chg(,,n,sa[i]+lcp+,n,sa[i]);
}
for(int i=;i<=n;i++)
{
int t=query(,,n,i,n+),p=ask(,,n,i,);
if(p==)printf("%d\n",t);//!
else printf("%d\n",min(t,i-p+));
}
return ;
}
bzoj 2865 字符串识别 —— 后缀数组的更多相关文章
- BZOJ 2865 字符串识别 | 后缀数组 线段树
集训讲字符串的时候我唯一想出正解的题-- 链接 BZOJ 2865 题面 给出一个长度为n (n <= 5e5) 的字符串,对于每一位,求包含该位的.最短的.在原串中只出现过一次的子串. 题解 ...
- bzoj 2865 字符串识别——后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 做出 ht[ ] 之后,sa[ ] 上每个位置和它前面与后面取 LCP ,其中较大的长 ...
- bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】
根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[ ...
- BZOJ 2865 字符串识别(后缀数组+线段树)
很容易想到只考虑后缀长度必须为\(max(height[rk[i]],height[rk[i]+1])+1\)(即\([i,i+x-1]\)代表的串只出现过一次)然后我正着做一遍反着做一遍,再取一个\ ...
- 【BZOJ4556】字符串(后缀数组,主席树)
[BZOJ4556]字符串(后缀数组,主席树) 题面 BZOJ 题解 注意看题: 要求的是\([a,b]\)的子串和[c,d]的\(lcp\)的最大值 先来一下暴力吧 求出\(SA\)之后 暴力枚举\ ...
- 【LOJ#3095】[SNOI2019]字符串(后缀数组)
[LOJ#3095][SNOI2019]字符串(后缀数组) 题面 LOJ 题解 首先画图看看如何比较两个串的大小,发现这个东西等价于求两个相邻的后缀的\(LCP\). 一个做法是求出\(SA\),然后 ...
- BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)
题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...
- bzoj 3277: 串 & bzoj 3473: 字符串【后缀自动机||后缀数组】
建一个广义后缀自动机(每加完一个串都返回root),在parent树上dpsum记录合法长度,打着时间戳往上跳,最后每个串在自动机上跑一变统计答案即可. 后缀数组理解起来可能方便一点,但是难写,就只说 ...
- BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)
题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...
随机推荐
- C语言高速入门系列(四)
C语言高速入门系列(四) C语言数组 ---------转载请注明出处:coder-pig 贴心小提示:假设图看不清晰可右键另存为,应该就非常清晰了; 注意上面的代码都要自己过一遍哦! 本节引言: 经 ...
- mysql数据库常用语句系列
mysql查询某个字段长度 一般查询语句:SELECT `lcontent` FROM `caiji_ym_liuyan` 查询数据: 有些时候需要查询某个字段的长度为多少时候才显示数据: SQL ...
- 详解spring boot实现多数据源代码实战
之前在介绍使用JdbcTemplate和Spring-data-jpa时,都使用了单数据源.在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.propertie ...
- python 基础 1.5 python数据类型(三)--元组常用方法示例
#/usr/bin/python#coding=utf-8#@Time :2017/10/13 15:02#@Auther :liuzhenchuan#@File :元组.py #tuple() 字符 ...
- GS与数据库打交道
GS与数据库打交道 link_stat stat = (link_stat)rPkt.size; if (stat == link_stat::link_connected) { GameChanne ...
- 兔子的晚会 2016Vijos省选集训 day1
兔子的晚会 (xor.c/pas/cpp)============================= 很久很久之前,兔子王国里居住着一群兔子.每到新年,兔子国王和他的守卫总是去现场参加晚会来欢庆新年. ...
- SAM4E单片机之旅——13、LCD之ASF初步
在Atmel Studio 6中,集成了Atmel Software Framework(ASF框架).通过它提供的库,可以很快速地完成新的项目. 这次的最终目标使用ASF在LCD上显示出文字“Hel ...
- 使用jdk中keytool生成证书
-genkey 在用户主目录中创建一个默认文件".keystore",还会产生一个mykey的别名,mykey中包含用户的公钥.私钥和证书 -alias 产生别名 -keystor ...
- HDU 5247 找连续数 (set妙用)
找连续数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- Web框架和Django基础
核心知识点 1.web应用类似于一个socket客户端,用来接收请求 2.HTTP:规定了客户端和服务器之间的通信格式. 3.一个HTTP包含两部分,header和body,body是可选,\r\n分 ...