您的位置:首页 > 其它

【BZOJ1396】识别子串&【BZOJ2865】字符串识别(后缀自动机)

2018-04-02 17:07 417 查看

题面

自从有了DBZOJ

终于有地方交权限题了

题解

很明显,只出现了一次的串

在SAM的right/endpos集合大小一定为1

换句话说,在parent树上是叶子节点

找到所有这样的节点,

假设它的len=r,它父亲的len=p,它的结束位置为显然就是r

令l=r−p

以r结尾,

并且只出现了一次的串的左端点

为1..l,那么,他们的答案可以更新为r+1−i

剩下的位置l+1..r,他们无法作为左端点,只能包含在这些串中

于是找到一个最短的包含他们的串S[l..r]

所以,这段区间的答案可以更新为r−l+1

显然不好一起维护,

于是开两棵线段树,一个维护r+1−i,先不考虑i,最后减去就好

另一个直接维护r−l+1

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define lson (now<<1)
#define rson (now<<1|1)
#define MAX 111111
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int n;
bool vis[MAX<<1];
struct SAM
{
struct Node
{
int son[26];
int ff,len;
}t[MAX<<1];
int last,tot;
void init(){last=tot=1;}
void extend(int c)
{
int p=last,np=++tot;last=np;
t[np].len=t[p].len+1;
while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
if(!p)t[np].ff=1;
else
{
int q=t[p].son[c];
if(t[q].len==t[p].len+1)t[np].ff=q;
else
{
int nq=++tot;
t[nq]=t[q];t[nq].len=t[p].len+1;
t[np].ff=t[q].ff=nq;
while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
}
}
}
}SAM;
char ch[MAX];
struct SegMentTree
{
struct Node{int v;}t[MAX<<2];
void Build(int now,int l,int r)
{
t[now].v=1e9;if(l==r)return;
int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
}
void puttag(int now,int w){t[now].v=min(t[now].v,w);}
void pushdown(int now)
{
if(t[now].v==1e9)return;
puttag(lson,t[now].v);puttag(rson,t[now].v);
t[now].v=1e9;
}
void Modify(int now,int l,int r,int L,int R,int w)
{
if(L>R)return;
if(L<=l&&r<=R){puttag(now,w);return;}
pushdown(now);int mid=(l+r)>>1;
if(L<=mid)Modify(lson,l,mid,L,R,w);
if(R>mid)Modify(rson,mid+1,r,L,R,w);
}
int Query(int now,int l,int r,int p)
{
if(l==r)return t[now].v;
pushdown(now);int mid=(l+r)>>1;
if(p<=mid)return Query(lson,l,mid,p);
else return Query(rson,mid+1,r,p);
}
}A,B;
int main()
{
SAM.init();
scanf("%s",ch+1);n=strlen(ch+1);
for(int i=1;i<=n;++i)SAM.extend(ch[i]-97);
for(int i=1;i<=SAM.tot;++i)vis[SAM.t[i].ff]=true;
A.Build(1,1,n);B.Build(1,1,n);
for(int i=1;i<=SAM.tot;++i)
if(!vis[i])
{
int l=SAM.t[i].len-SAM.t[SAM.t[i].ff].len,r=SAM.t[i].len;
A.Modify(1,1,n,l,r,r-l+1);
B.Modify(1,1,n,1,l-1,r+1);
}
for(int i=1;i<=n;++i)
printf("%d\n",min(A.Query(1,1,n,i),B.Query(1,1,n,i)-i));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: