作者:g我爱他偶买噶 | 来源:互联网 | 2023-07-28 20:35
题面题意:给出一个串串,对于每个位置求包含每个位置的,最短的,只出现一次的子串的长度由区间的套路,只要求出以每个位置为L,最小的R,设为f[L]rolepresentati
题面
题意:给出一个串串,对于每个位置
求包含每个位置的,最短的,只出现一次的子串的长度
由区间的套路,只要求出以每个位置为L,最小的R,设为f[L]" role="presentation" >
f[L]
显然f" role="presentation" >
f
单调不降
在后缀自动机上,考虑Right集大小为1的状态T
发现f[1]到f[dep[T]−Min(T)+1]" role="presentation" >
f[1]到f[dep[T]−Min(T)+1]
可用dep[T]更新
对于每个位置i,考虑以它为右端点
找到第一个f[h]<i" role="presentation" >
f[h]<i
的h,i-h+1可更新ans[i]
若不以其为右端点,则j&#x2208;[h+1,i]" role="presentation" >
j∈[h+1,i]
的f[j]&#x2212;j+1" role="presentation" >
f[j]−j+1
可更新ans[i]
单调队列维护即可
zenzen不用线段树哦
using namespace std;
typedef long long LL;
const int N=400200,oo=1e9+7;
int n;
int pre[N],dep[N],r[N],son[N][26],cnt=1,last=1;
int head[N],nex[N],to[N],cur;
int len[N],ans[N],q[N];
char s[N];
void add(int u,int v)
{
to[++cur]=v;
nex[cur]=head[u];
head[u]=cur;
}
void dfs(int x)
{
for(int h=head[x];h;h=nex[h])
dfs(to[h]),r[x]+=r[to[h]];
}
void Insert(int x)
{
dep[++cnt]=dep[last]+1;
int np=cnt,p=last;
last=cnt;
r[np]=1;
for(;!son[p][x];p=pre[p])
son[p][x]=np;
if(!p)
pre[np]=1;
else
{
int q=son[p][x];
if(dep[q]==dep[p]+1)
pre[np]=q;
else
{
dep[++cnt]=dep[p]+1;
int nq=cnt;
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
mmcp(son[nq],son[q]);
for(;son[p][x]==q;p=pre[p])
son[p][x]=nq;
}
}
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++)
Insert(s[i]-'a');
for(int i=2;i<=cnt;i++)
add(pre[i],i);
dfs(1);
for(int i=1;i<=n;i++)
ans[i]=len[i]=oo;
for(int i=2;i<=cnt;i++)
if(r[i]==1)
len[dep[i]-dep[pre[i]]]=min(len[dep[i]-dep[pre[i]]],dep[i]);
for(int i=n-1;i>=1;i--)
len[i]=min(len[i],len[i+1]);
int now=n,hh=1,tt=0;
for(int i=n;i>=1;i--)
{
while(now>=1&&len[now]>i)
{
while(hh<=tt&&len[q[tt]]-q[tt]>=len[now]-now)
tt--;
if(len[now]!=oo&&now<=i)
q[++tt]=now;
now--;
}
if(now)
ans[i]=min(ans[i],i-now+1);
if(hh<=tt)
ans[i]=min(ans[i],len[q[hh]]-q[hh]+1);
if(q[hh]==i)
hh++;
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}