题目描述
题解
这题思路还是比较好想的
建立后缀自动机了之后统计每一个点right集合的大小,若一个点right集合的大小为1,那么以这个点为右端点的合法子串都是只在字符串中出现过一遍的,所谓合法就是长度在这个点的长度区间[Min,Max]里,这个点在原串中的位置也就是step
那么如何求每一个位置的最小值呢?
假设某一个点right集合大小为1,右端点为step,合法的长度区间为[Min,Max],那么显然[r-Min+1,r]中的点长度都可以取Min,而[r-Max+1,r-Min]中的点i长度都可以取Max-i+1,这就是一些区间修改的问题了
但是并不能用线段树直接维护,因为修改的东西不一样!但是可以发现[r-Min+1,r]和[r-Max+1,r-Min]可以分开修改,前者直接修改长度,后者修改向右边最近的点
就是要写两棵线段树了..
想了想好像sa也是可以写的,就是搞出来height了之后对于每一个和前后取一下min,然后线段树的处理方法和sam是差不多的,有时间写一写吧
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 200005
char s[N];
int n,root,sz,last,p,np,q,nq;
int ch[N][30],pre[N],step[N],c[N],pt[N],rt[N],loc[N];
void extend()
{
root=last=++sz;
for (int i=1;i<=n;++i)
{
int x=s[i]-'a';
p=last;np=++sz;last=np;
step[np]=step[p]+1;
while (p&&!ch[p][x])
{
ch[p][x]=np;
p=pre[p];
}
if (!p) pre[np]=root;
else
{
q=ch[p][x];
if (step[q]==step[p]+1) pre[np]=q;
else
{
nq=++sz;
step[nq]=step[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
pre[nq]=pre[q];
while (ch[p][x]==q)
{
ch[p][x]=nq;
p=pre[p];
}
pre[np]=pre[q]=nq;
}
}
}
}
namespace Segtreeval
{
int mn[N*4],delta[N*4],inf;
void init()
{
memset(mn,127,sizeof(mn));
memset(delta,127,sizeof(delta));
inf=mn[0];
}
void update(int now)
{
mn[now]=min(mn[now<<1],mn[now<<1|1]);
}
void pushdown(int now)
{
if (delta[now]!=inf)
{
mn[now<<1]=min(mn[now<<1],delta[now]);
delta[now<<1]=min(delta[now<<1],delta[now]);
mn[now<<1|1]=min(mn[now<<1|1],delta[now]);
delta[now<<1|1]=min(delta[now<<1|1],delta[now]);
delta[now]=inf;
}
}
void change(int now,int l,int r,int lr,int rr,int x)
{
if (lr>rr) return;
int mid=(l+r)>>1;
if (lr<=l&&r<=rr)
{
mn[now]=min(mn[now],x);
delta[now]=min(delta[now],x);
return;
}
pushdown(now);
if (lr<=mid) change(now<<1,l,mid,lr,rr,x);
if (mid+1<=rr) change(now<<1|1,mid+1,r,lr,rr,x);
update(now);
}
int query(int now,int l,int r,int x)
{
int mid=(l+r)>>1;
if (l==r) return mn[now];
pushdown(now);
if (x<=mid) return query(now<<1,l,mid,x);
else return query(now<<1|1,mid+1,r,x);
}
}
namespace Segtreeloc
{
int mn[N*4],delta[N*4],inf;
void init()
{
memset(mn,127,sizeof(mn));
memset(delta,127,sizeof(delta));
inf=mn[0];
}
void update(int now)
{
mn[now]=min(mn[now<<1],mn[now<<1|1]);
}
void pushdown(int now)
{
if (delta[now]!=inf)
{
mn[now<<1]=min(mn[now<<1],delta[now]);
delta[now<<1]=min(delta[now<<1],delta[now]);
mn[now<<1|1]=min(mn[now<<1|1],delta[now]);
delta[now<<1|1]=min(delta[now<<1|1],delta[now]);
delta[now]=inf;
}
}
void change(int now,int l,int r,int lr,int rr,int x)
{
if (lr>rr) return;
int mid=(l+r)>>1;
if (lr<=l&&r<=rr)
{
mn[now]=min(mn[now],x);
delta[now]=min(delta[now],x);
return;
}
pushdown(now);
if (lr<=mid) change(now<<1,l,mid,lr,rr,x);
if (mid+1<=rr) change(now<<1|1,mid+1,r,lr,rr,x);
update(now);
}
int query(int now,int l,int r,int x)
{
int mid=(l+r)>>1;
if (l==r) return mn[now];
pushdown(now);
if (x<=mid) return query(now<<1,l,mid,x);
else return query(now<<1|1,mid+1,r,x);
}
}
int main()
{
scanf("%s",s+1);n=strlen(s+1);
extend();
for (int i=1;i<=sz;++i) ++c[step[i]];
for (int i=1;i<=sz;++i) c[i]+=c[i-1];
for (int i=sz;i>=1;--i) pt[c[step[i]]--]=i;
p=root;
for (int i=1;i<=n;++i)
{
int x=s[i]-'a';
p=ch[p][x];
++rt[p];loc[p]=step[p];
}
for (int i=sz;i>=1;--i)
{
p=pt[i];
rt[pre[p]]+=rt[p],loc[pre[p]]=loc[p];
}
Segtreeval::init();Segtreeloc::init();
for (int i=1;i<=sz;++i)
if (rt[i]==1)
{
int a=loc[i];
int b=a-step[pre[i]];
Segtreeval::change(1,1,n,b,a,step[pre[i]]+1);
int c=a-step[i]+1;
Segtreeloc::change(1,1,n,c,b-1,loc[i]);
}
for (int i=1;i<=n;++i)
{
int ans=min(Segtreeval::query(1,1,n,i),Segtreeloc::query(1,1,n,i)-i+1);
printf("%d\n",ans);
}
}