[BZOJ1396] 识别子串

Description

img

Input

一行,一个由小写字母组成的字符串S,长度不超过10^5

Output

L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

Solution

建后缀自动机。

对于每个\(sz\)\(0\)的点可以造成两段贡献,一段直线,一段斜率为\(-1\)的斜线。

水平的线直接线段树维护就好了,斜率\(-1\)的可以那个数组记一下然后倒着枚举统计答案就好了,这步不是很好讲...可以看看代码中标记部分。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;
const int inf = 1e9;

char s[maxn];
int cnt,lstp;
int ml[maxn],par[maxn],pos[maxn],tr[maxn][26],sz[maxn],sum[maxn],rr[maxn];

void append(int x,int i) {
	int p=lstp,np=++cnt;pos[np]=i,ml[np]=ml[p]+1;sz[np]=1;lstp=np;
	for(;p&&tr[p][x]==0;p=par[p]) tr[p][x]=np;
	if(!p) return par[np]=1,void();
	int q=tr[p][x];
	if(ml[p]+1<ml[q]) {
		int nq=++cnt;ml[nq]=ml[p]+1;pos[nq]=pos[q];
		memcpy(tr[nq],tr[q],sizeof tr[nq]);
		par[nq]=par[q],par[q]=par[np]=nq;
		for(;p&&tr[p][x]==q;p=par[p]) tr[p][x]=nq;
	} else par[np]=q;
}

void prepare() {
	for(int i=1;i<=cnt;i++) sum[ml[i]]++;
	for(int i=1;i<=cnt;i++) sum[i]+=sum[i-1];
	for(int i=1;i<=cnt;i++) rr[sum[ml[i]]--]=i;

	for(int i=cnt;i;i--) sz[par[rr[i]]]+=sz[rr[i]];
}

#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)

int tag[maxn<<1],t[maxn<<1],ns[maxn],ans[maxn];

void push_tag(int p,int v) {t[p]=min(t[p],v),tag[p]=min(tag[p],v);}
void pushdown(int p) {if(tag[p]!=inf) push_tag(ls,tag[p]),push_tag(rs,tag[p]),tag[p]=inf;}

void build(int p,int l,int r) {
	t[p]=tag[p]=inf;
	if(l==r) return ;
	build(ls,l,mid),build(rs,mid+1,r);
}

void modify(int p,int l,int r,int x,int y,int v) {
	if(x<=l&&r<=y) return push_tag(p,v),void();
	pushdown(p);
	if(x<=mid) modify(ls,l,mid,x,y,v);
	if(y>mid) modify(rs,mid+1,r,x,y,v);
}

void dfs(int p,int l,int r) {
	if(l==r) return ans[l]=t[p],void();
	pushdown(p);dfs(ls,l,mid),dfs(rs,mid+1,r);
}

int main() {
	scanf("%s",s+1);int n=strlen(s+1);cnt=lstp=1;
	for(int i=1;i<=n;i++) append(s[i]-'a',i);
	build(1,1,n);prepare();
	for(int i=1;i<=n;i++) ns[i]=inf;
	for(int i=1;i<=cnt;i++) {
		if(sz[i]!=1) continue;
		int l=pos[i]-ml[i]+1,r=pos[i]-ml[par[i]];
		if(l!=r) ns[r-1]=min(ns[r-1],pos[i]-r+2);
		modify(1,1,n,r,pos[i],ml[par[i]]+1);
	}
	dfs(1,1,n);int p=inf;
	for(int i=n;i;i--) p=min(p+1,ns[i]),ans[i]=min(ans[i],p);   //slope -1 solved here
	for(int i=1;i<=n;i++) write(ans[i]);
	return 0;
}
posted @ 2019-03-13 15:29  Hyscere  阅读(189)  评论(0编辑  收藏  举报