其他分享
首页 > 其他分享> > [BZOJ1396] 识别子串

[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;
}

标签:子串,ch,int,void,mid,dfs,识别,BZOJ1396,getchar
来源: https://www.cnblogs.com/hbyer/p/10523474.html