题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865

做出 ht[ ] 之后,sa[ ] 上每个位置和它前面与后面取 LCP ,其中较大的长度设为 d ,表示从 sa[ i ] 位置开始的子串的右端点要在 sa[ i ]+d-1 位置之后才是只出现了一次的。

那么 sa[ i ] ~ sa[ i ]+d 位置的答案可以对 d+1 取 min ;至于 sa[ i ]+d+1 ~ n 位置,sa[ i ]可能成为它们答案的开头位置,所以可以维护每个位置备选答案串开头的最靠后位置(这样最靠近自己),让 sa[ i ]+d+1 ~ n 位置的这个值对 sa[ i ] 取 max 就行了。可以用线段树维护。

注意那个“备选答案串开头的最靠后位置”的初值不是0!不然第一个位置有可能和第0个位置组合了。应该是 -n 之类,才能排除影响。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
const int N=5e5+,M=N<<;
int n,sa[N],rk[N],tp[N],tx[N],ht[N];
int tot,Ls[M],Rs[M],tg1[M],tg2[M];
int ans[N]; char s[N];
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
void Rsort(int n,int nm)
{
for(int i=;i<=nm;i++)tx[i]=;
for(int i=;i<=n;i++)tx[rk[i]]++;
for(int i=;i<=nm;i++)tx[i]+=tx[i-];
for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
}
void get_sa(int n)
{
int nm=;
for(int i=;i<=n;i++)tp[i]=i,rk[i]=s[i];
Rsort(n,nm);
for(int k=;k<=n;k<<=)
{
int tot=;
for(int i=n-k+;i<=n;i++)tp[++tot]=i;
for(int i=;i<=n;i++)
if(sa[i]>k)tp[++tot]=sa[i]-k;
Rsort(n,nm);memcpy(tp,rk,sizeof rk);
nm=;rk[sa[]]=;
for(int i=,u,v;i<=n;i++)
{
u=sa[i]+k;v=sa[i-]+k;if(u>n)u=;if(v>n)v=;
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[u]==tp[v])?nm:++nm;
}
if(nm==n)break;
}
}
void get_ht(int n)
{
for(int i=,k=,j;i<=n;i++)
{
for(k?k--:,j=sa[rk[i]-];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
ht[rk[i]]=k;//rk[i]!!!
}
}
void build(int l,int r,int cr)
{
tg1[cr]=n+; tg2[cr]=-n;////
if(l==r)return; int mid=l+r>>;
ls=++tot; build(l,mid,ls);
rs=++tot; build(mid+,r,rs);
}
void mdfy(int l,int r,int cr,int L,int R,int k)
{
if(l>=L&&r<=R){tg1[cr]=Mn(tg1[cr],k);return;}
int mid=l+r>>;
if(L<=mid)mdfy(l,mid,ls,L,R,k);
if(mid<R)mdfy(mid+,r,rs,L,R,k);
}
void mdfyx(int l,int r,int cr,int L,int R,int k)
{
if(l>=L&&r<=R){tg2[cr]=Mx(tg2[cr],k);return;}
int mid=l+r>>;
if(L<=mid)mdfyx(l,mid,ls,L,R,k);
if(mid<R)mdfyx(mid+,r,rs,L,R,k);
}
void dfs(int l,int r,int cr,int lj1,int lj2)
{
lj1=Mn(lj1,tg1[cr]); lj2=Mx(lj2,tg2[cr]);//before l==r
if(l==r){ans[l]=Mn(lj1,l-lj2+);return;}
int mid=l+r>>;
dfs(l,mid,ls,lj1,lj2); dfs(mid+,r,rs,lj1,lj2);
}
int main()
{
scanf("%s",s+);n=strlen(s+);
get_sa(n); get_ht(n);
tot=;build(,n,);
for(int i=,d;i<=n;i++)
{
d=sa[i]+Mx(ht[i],ht[i+]); if(d>n)continue;
mdfy(,n,,sa[i],d,d-sa[i]+);
if(d<n)mdfyx(,n,,d+,n,sa[i]);
}
dfs(,n,,n+,-n);//-n
for(int i=;i<=n;i++)printf("%d\n",ans[i]);
return ;
}

bzoj 2865 字符串识别——后缀数组的更多相关文章

  1. BZOJ 2865 字符串识别 | 后缀数组 线段树

    集训讲字符串的时候我唯一想出正解的题-- 链接 BZOJ 2865 题面 给出一个长度为n (n <= 5e5) 的字符串,对于每一位,求包含该位的.最短的.在原串中只出现过一次的子串. 题解 ...

  2. bzoj 2865 字符串识别 —— 后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2865 唯一出现的子串就是每个后缀除去和别的后缀最长的 LCP 之外的前缀: 所以用这个更新一 ...

  3. bzoj 1396: 识别子串 && bzoj 2865: 字符串识别【后缀数组+线段树】

    根据height数组的定义,和当前后缀串i最长的相同串的长度就是max(height[i],height[i+1]),这个后缀贡献的最短不同串长度就是len=max(height[i],height[ ...

  4. BZOJ 2865 字符串识别(后缀数组+线段树)

    很容易想到只考虑后缀长度必须为\(max(height[rk[i]],height[rk[i]+1])+1\)(即\([i,i+x-1]\)代表的串只出现过一次)然后我正着做一遍反着做一遍,再取一个\ ...

  5. 【BZOJ4556】字符串(后缀数组,主席树)

    [BZOJ4556]字符串(后缀数组,主席树) 题面 BZOJ 题解 注意看题: 要求的是\([a,b]\)的子串和[c,d]的\(lcp\)的最大值 先来一下暴力吧 求出\(SA\)之后 暴力枚举\ ...

  6. 【LOJ#3095】[SNOI2019]字符串(后缀数组)

    [LOJ#3095][SNOI2019]字符串(后缀数组) 题面 LOJ 题解 首先画图看看如何比较两个串的大小,发现这个东西等价于求两个相邻的后缀的\(LCP\). 一个做法是求出\(SA\),然后 ...

  7. BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)

    题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...

  8. bzoj 3277: 串 & bzoj 3473: 字符串【后缀自动机||后缀数组】

    建一个广义后缀自动机(每加完一个串都返回root),在parent树上dpsum记录合法长度,打着时间戳往上跳,最后每个串在自动机上跑一变统计答案即可. 后缀数组理解起来可能方便一点,但是难写,就只说 ...

  9. BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)

    题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...

随机推荐

  1. iOS动画进阶 - 手摸手教你写 Slack 的 Loading 动画

    如果移动端访问不佳,可以访问我的个人博客 前几天看了一篇关于动画的博客叫手摸手教你写 Slack 的 Loading 动画,看着挺炫,但是是安卓版的,寻思的着仿造着写一篇iOS版的,下面是我写这个动画 ...

  2. Node.Js安装教程

    Node.Js安装教程 介绍下我的环境 环境 值 操作系统 win10 64bit Node.Js 8.9.4 emmmm 表格中毒了,为什么出不来效果 一.下载及安装 这个可以去Node.Js官网上 ...

  3. javascript练习题(2):变量作用域

    1. 外层变量在内部可以找到,反之找不到 以下看个案例: var a=10; function aaa(){ alert(a); } function bbb(){ var a=20; aaa(); ...

  4. IFE 2015_spring task0002 自学记录

    JavaScript数据类型及语言基础 1. 判断arr是不是一个数组,返回一个bool值. 首先javascript有5大基本数据类型:Undefined,Null,Boolean,Number和S ...

  5. Java中异常的捕获顺序(多个catch)

    import java.io.IOException; public class ExceptionTryCatchTest { public void doSomething() throws IO ...

  6. H5测试

    H5是什么? H5的全称是HTML5,其实就是:移动端WEB页面. H5与原生 APP的区别: APP是使用原生系统内核的,相当于直接在系统上操作,是我们传统意义上的软件,更加稳定. H5的APP先得 ...

  7. Ajax-02 iframe实现伪“Ajax”

    需求: 用户输入URL,使用iframe将目标URL的内容加载到页面指定位置(局部刷新) <!DOCTYPE html> <html lang="en"> ...

  8. java 数据库索引的注意事项

    索引缺点 1.虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行insert.update和delete.因为更新表时,不仅要保存数据,还要保存一下索引文件.2.建立索引会占用磁盘空间的 ...

  9. react-redux: async promise

    1.the simple sample action: 事实上,只是返回个一个至少包含type的对象{ },用于reducer接收. import {RECEIVE_DATA} from " ...

  10. canvas - 圆圈内 hover 高亮 效果

    各种计算还挺繁琐的, 关键点在角度的计算, 根据鼠标位置, 利用atan(y/x) 得到反正切值 , 角度  (tan输入的是r和x围成的那个角,输出的是y/x.反tan就是输入y/x输出角.) &l ...