题目: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. Floyd算法 - 最短路径

    2017-07-27 22:21:04 writer:pprp 该算法的本质是动态规划,形式简单,复杂度高为O(n^3): d[i][j] = max(d[i][k]+d[k][j],d[i][j]) ...

  2. Linux平台下Oracle定时备份数据

    临时收到一个任务,就是在生产环境上定时备份oracle的数据.空闲时间搞了一下,真是一波三折,过程有点小郁闷,结果哈哈.现在进行总结一下 (1)新建一个shell脚本test.sh #!/bin/ba ...

  3. MySQL无法启动几种常见问题小结

    问题1:目录.文件权限设置不正确 MySQL的$datadir目录,及其下属目录.文件权限属性设置不正确,导致MySQL无法正常读写文件,无法启动. 错误信息例如: 复制代码 代码如下:[code] ...

  4. OnTouch关于performClick的Warning

    OnTouch关于performClick的Warning 当你对一个控件(例如FloatingActionButton)使用setOnTouchListener() 或者是对你的自定义控件重写onT ...

  5. LeetCode第[42]题(Java):Trapping Rain Water (数组方块盛水)——HARD

    题目:接雨水 难度:hard 题目内容: Given n non-negative integers representing an elevation map where the width of ...

  6. 20165332实验二 Java面向对象程序设计

    20165332实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验要求 ...

  7. request方法传入动态参数的一个"误区"

    晚上写了一个请求类,传了一个动态参数进去,实例化测试的时候,发现请求数据根本没法读到,先附上代码 import requests class MyRequests: def send_request( ...

  8. spring boot配置德鲁伊

    1.引入相关依赖,全部依赖是上一篇spring boot+mybatis依赖的基础上,再加上下边的依赖,如下: <!-- Druid数据库连接池组件 --> <dependency& ...

  9. neutron之SDN简单测试

    title: Neutron SDN 手动实现手册 date: 2017-04-13 23:37 tags: Network 本文旨在通过自己搭建类似neutron (openvswitch + gr ...

  10. 【OpenGL ES】关于VBO(Vertex Buffer Object)的一些坑——解析一些关于glBuffer的函数

    最近在写毕设的时候用到OpenGL ES中的VBO,由于对一些接口用到的变量不了解被坑得很惨,在此记录一下防止以后再被坑. 本文为大便一箩筐的原创内容,转载请注明出处,谢谢:http://www.cn ...