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

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

题面

自从有了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;
}


posted @ 2018-04-02 17:09  小蒟蒻yyb  阅读(566)  评论(2编辑  收藏  举报