【BZOJ1396】识别子串 - 后缀自动机+线段树

题意:

Description

Input

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

Output

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

题解:

先建出SAM,显然right集合大小为1的子串,即在parent树上的叶子节点可以作为识别子串;

考虑一个这样的子串会对哪些区间产生影响:

设$l=max[fa[s]]$,$r=max[s]$,显然这个子串出现的位置就是$r$,所以对区间$[1,r]$都有影响;

但是其中有一段是被$fa[s]$包含的,因此贡献不同,具体来说就是:

在区间$[1,l-1]$中贡献为$r-i+1$;

在区间$[l,r]$中贡献为$r-l+1$;

这里手推一下就好;

因此开两棵线段树维护修改最小值即可。

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #include<set>
 8 #define inf 0x7f7f7f7f
 9 #define eps 1e-9
10 #define mp make_pair
11 using namespace std;
12 typedef long long ll;
13 typedef double db;
14 int n,l,r,last=1,rt=1,tot=1,son[200001][26],fa[200001],mx[200001];
15 bool ch[200001];
16 char s[100001];
17 struct seg{
18     int t[2000001];
19     seg(){
20         memset(t,0x7f,sizeof(t));
21     }
22     void pd(int u){
23         if(t[u]!=inf){
24             t[u*2]=min(t[u*2],t[u]);
25             t[u*2+1]=min(t[u*2+1],t[u]);
26             t[u]=inf;
27         }
28     }
29     void updata(int l,int r,int u,int L,int R,int x){
30         if(L>R)return;
31         if(L<=l&&r<=R){
32             t[u]=min(t[u],x);
33             return;
34         }
35         pd(u);
36         int mid=(l+r)/2;
37         if(L<=mid)updata(l,mid,u*2,L,R,x);
38         if(mid<R)updata(mid+1,r,u*2+1,L,R,x);
39     }
40     int query(int l,int r,int u,int p){
41         if(l==r)return t[u];
42         pd(u);
43         int mid=(l+r)/2;
44         if(p<=mid)return query(l,mid,u*2,p);
45         else return query(mid+1,r,u*2+1,p);
46     }
47 }t1,t2;
48 void extend(int ch){
49     int p=last,np=++tot;
50     mx[np]=mx[p]+1;
51     for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np;
52     if(!p)fa[np]=rt;
53     else{
54         int q=son[p][ch];
55         if(mx[q]==mx[p]+1)fa[np]=q;
56         else{
57             int nq=++tot;
58             mx[nq]=mx[p]+1;
59             memcpy(son[nq],son[q],sizeof(son[q]));
60             fa[nq]=fa[q];
61             fa[q]=fa[np]=nq;
62             for(;p&&son[p][ch]==q;p=fa[p])son[p][ch]=nq;
63         }
64     }
65     last=np;
66 }
67 int main(){
68     scanf("%s",s);
69     n=strlen(s);
70     for(int i=0;i<n;i++)extend(s[i]-'a');
71     for(int i=1;i<=tot;i++){
72         if(fa[i])ch[fa[i]]=true;
73     }
74     for(int i=1;i<=tot;i++){
75         if(!ch[i]){
76             l=mx[i]-mx[fa[i]],r=mx[i];
77             t1.updata(1,n,1,1,l-1,r+1);
78             t2.updata(1,n,1,l,r,r-l+1);
79         }
80     }
81     for(int i=1;i<=n;i++){
82         printf("%d\n",min(t1.query(1,n,1,i)-i,t2.query(1,n,1,i)));
83     }
84     return 0;
85 }
posted @ 2018-12-17 09:11  DCDCBigBig  阅读(213)  评论(0编辑  收藏  举报