题目: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. Effective C++ 条款03:尽可能使用const

    场景一 用于修饰指针 char greeting[] = "Hello"; char* p = greeting; // non-const pointer, non-const ...

  2. 多线程-信号量Semaphore

    计数信号量用来控制同时访问某个特定资源的操作数量.Semaphore可以用于实现资源池,例如数据库连接池.我们可以构造一个固定长度的资源池,当资源池为空的时候,请求资源将会阻塞,而不是失败.当资源池非 ...

  3. 比较好的SQL

    DECLARE @Data NVARCHAR(30);DECLARE @Data2 NVARCHAR(30);SET @Data = @DataDate;SET @Data = CONVERT(CHA ...

  4. Spring -- aop, 用Aspectj进行AOP开发

    1. 概要 添加类库:aspectjrt.jar和aspectjweaver.jar 添加aop schema. 定义xml元素:<aop:aspectj-autoproxy> 编写jav ...

  5. Reverse Nodes In K Group,将链表每k个元素为一组进行反转---特例Swap Nodes in Pairs,成对儿反转

    问题描述:1->2->3->4,假设k=2进行反转,得到2->1->4->3:k=3进行反转,得到3->2->1->4 算法思想:基本操作就是链表 ...

  6. tyvj 1059 过河 dp

    P1059 过河 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 NOIP2005 提高组 第二道 描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳 ...

  7. redis的Python接口调用

    Redis安装及教程: redis教程 安装Python的redis接口模块 redis-py requires a running Redis server. See redis教程 for ins ...

  8. spring3: 表达式5.2 SpEL基础

    5.1  概述 5.1.1  概述 Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”,类似于Struts2x中使用的OGNL表达式语言,能在运行 ...

  9. Linux:安装git

    1.下载 https://www.kernel.org/pub/software/scm/git/git-2.9.4.tar.gz 2.解压 tar zxvf git-2.9.4.tar.gz cd  ...

  10. 《The Cg Tutorial》阅读笔记——光照 Lighting

    本文为大便一箩筐的原创内容,转载请注明出处,谢谢:http://www.cnblogs.com/dbylk/p/4796306.html 光照 Lighting 一.常见的几种光照模型 二.基本的光照 ...