[BZOJ1396] 识别子串
作者:互联网
Description
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;
}
标签:子串,ch,int,void,mid,dfs,识别,BZOJ1396,getchar 来源: https://www.cnblogs.com/hbyer/p/10523474.html