题目: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 ;
}

最新文章

  1. VPython 三维显示 —— hello word
  2. 为了体验 ILS 在Win2012R2 Hyper-V上安装Windows 2000 AdvSer
  3. 手写PE文件(二)
  4. wait、waitpid 僵尸进程 孤儿进程
  5. 【软件分享】文本对比工具 Beyond Compare
  6. 【转】Memcached管理与监控工具----MemAdmin
  7. Django学习(六) 模板
  8. JavaScript实例技巧精选(14)—动态变化背景颜色
  9. ArcGIS Pro 简明教程(1)Pro简介
  10. canvas绘制一定数目的圆(均分)
  11. wpf研究之道——datagrid控件数据绑定
  12. python3 多线程的使用
  13. JavaWeb+SVN+Maven+Tomcat +jenkins实现自动化部署
  14. Linux之prink原理
  15. I/O 机制的介绍(Linux 中直接 I/O 机制的介绍)
  16. mongodb配置、启动、备份
  17. [UE4]Switch on String,根据字符串决定条件分支,类似于高级语言中的switch语句
  18. 红黑树,TreeMap,插入操作
  19. Visual Studio 2017 远程调试(Remote Debugger)应用
  20. 【zTree】zTree展开树节点

热门文章

  1. iOS 或者Android调用vue.js 里面的方法
  2. Linux平台下Oracle定时备份数据
  3. JAVA 泛型意淫之旅(二)
  4. python学习笔记(excel中处理日期格式)
  5. ubuntu16.04 运行elasticfusion
  6. lightoj1197区间素数筛
  7. mysql-5.7.17的最新安装教程
  8. LeetCode OJ:Jump Game(跳跃游戏)
  9. windows7自动登录后锁定 &amp; 其他VBS
  10. jsp中的session