BZOJ1396 识别子串

传送门

题目大意

给定一个字符串,求对于每一个位置,求包含它的只出现一次的子串的最短长度。

 

题解

先建后缀自动机,对于每一个$|Endpos|=1$的节点,设其右端点为$r$。

对于所有$x\in [r-minlen+1,r]$,可以用$minlen$的长度更新答案。

对于所有$x\in [r-maxlen+1,r-minlen]$,可以用$r-x$的长度更新。

用线段树维护两个标记,一个用来更新能够覆盖答案的最小长度$minlen$,即情况一,另一个用来更新能够用来更新答案的最左的右端点$r$,即情况二。

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
using namespace std;
namespace IO{
	const int BS=(1<<20); int Top=0;
	char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return *HD++;}
	void flush(){fwrite(OT,1,OS-OT,stdout);}
	void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
	void write(int x){
		if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
		while(x) SS[++Top]=x%10,x/=10;
		while(Top) Putchar(SS[Top]+'0'),--Top; Putchar('\n');
	}
	int read(){
		int nm=0,fh=1; char cw=Getchar();
		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
		return nm*fh;
	}
}
using namespace IO;
char S[M]; int n;
namespace segtree{
	int tg[M<<1][2];
	void init(){memset(tg,0x3f,sizeof(tg));}
	void mdf(int x,int l,int r,int L,int R,int dt,int kd){
		if(L<=l&&r<=R){tg[x][kd]=min(dt,tg[x][kd]);return;}
		if(r<L||R<l) return; int mid=((l+r)>>1);
		mdf(x<<1,l,mid,L,R,dt,kd),mdf(x<<1|1,mid+1,r,L,R,dt,kd);
	}
	void qry(int x,int l,int r,int ps,int len){
		ps=min(ps,tg[x][0]),len=min(len,tg[x][1]);
		if(l==r){write(min(ps-l+1,len));return;} int mid=((l+r)>>1);
		qry(x<<1,l,mid,ps,len),qry(x<<1|1,mid+1,r,ps,len);
	}
}
namespace SAM{
	int len[M],rs[M],fa[M],t[M][26],F[M],C[M],T[M];
	int now,cnt,ed,vs[M],sz[M],ps[M];
	void init(){cnt=ed=1,now=0,memset(rs,-1,sizeof(rs));}
	void ins(int c){
		int x=ed; len[ed=++cnt]=++now,rs[ed]=now,sz[ed]=1;
		while(x&&!t[x][c]) t[x][c]=ed,x=fa[x];
		if(!x){fa[ed]=1;return;} int y=t[x][c];
		if(len[y]==len[x]+1){fa[ed]=y;return;}
		len[++cnt]=len[x]+1,fa[cnt]=fa[y],fa[y]=fa[ed]=cnt;
		memcpy(t[cnt],t[y],sizeof(t[y]));
		while(x&&t[x][c]==y) t[x][c]=cnt,x=fa[x];
	}
	void build(){
		for(int i=1;i<=cnt;i++) C[len[i]]++;
		for(int i=1;i<=n;i++) C[i]+=C[i-1];
		for(int i=1;i<=cnt;i++) T[C[len[i]]--]=i;
		for(int i=cnt;i>0;i--){
			int x=T[i]; sz[fa[x]]+=sz[x];
			if(sz[x]) rs[fa[x]]=rs[x]; if(sz[x]>1||!sz[x]) continue;
			segtree::mdf(1,1,n,rs[x]-len[fa[x]],rs[x],len[fa[x]]+1,1);
			segtree::mdf(1,1,n,rs[x]-len[x]+1,rs[x]-len[fa[x]]-1,rs[x],0);
		}
	}
}
int main(){
	scanf("%s",S+1),n=strlen(S+1),SAM::init();
	for(int i=1;i<=n;i++) SAM::ins(S[i]-'a');
	segtree::init(),SAM::build();
	segtree::qry(1,1,n,M,M),flush();return 0;
}

 

posted @ 2018-10-18 16:49  OYJason  阅读(203)  评论(0编辑  收藏  举报