1. 程式人生 > >BZOJ1396: 識別子串(後綴自動機,線段樹)

BZOJ1396: 識別子串(後綴自動機,線段樹)

ans 距離 text inpu EDA algo 帶來 有效 can

Description

技術分享圖片

Input

一行,一個由小寫字母組成的字符串S,長度不超過10^5

Output

L行,每行一個整數,第i行的數據表示關於S的第i個元素的最短識別子串有多長.

Sample Input

agoodcookcooksgoodfood

Sample Output

1
2
3
3
2
2
3
3
2
2
3
3
2
1
2
3
3
2
1
2
3
4

解題思路:

思考一個最小識別串會帶來什麽。

在它內部的點的答案就是這個串的長度,而在它外面的點需要拓展到這個串的端點。

首先,一個Parent樹內的節點對應子串是唯一識別的,那麽其|Right|必定=1,那麽對應一個|Right|=1的節點

因為Parent樹上的節點是其子節點的後綴,而Parent樹是逆序的,所以一棵|Right|=1的子樹內結尾是一定的,設為endpos。

那麽在一個|Right|=1的節點內其有效壓縮長度為len-len[fa],那麽這段子串可以認為是等價唯一的。其長度為其到endpos的距離。

而在len[fa]以下的,識別長度太小必須使用len[fa]為最小識別長度。

區間修改當然要線段樹了。

len[fa]~len區間內,其答案為endpos-pos+1

1~len[fa]區間內,其答案為len[fa]

pos是與位置有關的變量最後算。

只需將endpos-1,len[fa]推入線段樹好了

代碼:

(不要問我為什麽上次拓撲這次建邊因為我閑的)

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define lll spc<<1
  5 #define rrr spc<<1|1
  6 struct sant{
  7     int tranc[26];
  8     int len;
  9     int pre;
 10 }s[1000000];
 11 struct pnt{
 12     int
hd; 13 int wgt; 14 int endp; 15 }p[1000000]; 16 struct ent{ 17 int twd; 18 int lst; 19 }e[1000000]; 20 struct trnt{ 21 int minval; 22 int lzt; 23 bool al; 24 }; 25 int cnt; 26 int siz; 27 int fin; 28 int n; 29 char tmp[1000000]; 30 class Sgmt_tree{ 31 public: 32 void res(void) 33 { 34 for(int i=0;i<500000;i++) 35 tr[i].lzt=tr[i].minval=0x3f3f3f3f; 36 return ; 37 } 38 void pushup(int spc) 39 { 40 tr[spc].minval=std::min(tr[lll].minval,tr[rrr].minval); 41 return ; 42 } 43 void Add(int spc,int x) 44 { 45 tr[spc].minval=std::min(tr[spc].minval,x); 46 tr[spc].lzt=std::min(tr[spc].lzt,x); 47 tr[spc].al=true; 48 return ; 49 } 50 void pushdown(int spc) 51 { 52 if(tr[spc].al) 53 { 54 Add(lll,tr[spc].lzt); 55 Add(rrr,tr[spc].lzt); 56 tr[spc].al=false; 57 } 58 return ; 59 } 60 void update(int l,int r,int ll,int rr,int spc,int v) 61 { 62 if(l>rr||ll>r) 63 return ; 64 if(ll<=l&&r<=rr) 65 { 66 Add(spc,v); 67 return ; 68 } 69 int mid=(l+r)>>1; 70 pushdown(spc); 71 update(l,mid,ll,rr,lll,v); 72 update(mid+1,r,ll,rr,rrr,v); 73 pushup(spc); 74 return ; 75 } 76 int query(int l,int r,int pos,int spc) 77 { 78 if(l==r) 79 return tr[spc].minval; 80 int mid=(l+r)>>1; 81 pushdown(spc); 82 if(pos<=mid) 83 return query(l,mid,pos,lll); 84 else 85 return query(mid+1,r,pos,rrr); 86 } 87 private: 88 trnt tr[500000]; 89 }T[2]; 90 void Insert(int c,int w) 91 { 92 int nwp,nwq,lsq,lsp; 93 nwp=++siz; 94 p[nwp].wgt=1; 95 p[nwp].endp=w; 96 s[nwp].len=s[fin].len+1; 97 for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre) 98 s[lsp].tranc[c]=nwp; 99 if(!s[lsp].tranc[c]) 100 s[lsp].tranc[c]=nwp; 101 else{ 102 lsq=s[lsp].tranc[c]; 103 if(s[lsq].len==s[lsp].len+1) 104 s[nwp].pre=lsq; 105 else{ 106 nwq=++siz; 107 s[nwq]=s[lsq]; 108 s[nwq].len=s[lsp].len+1; 109 s[nwp].pre=s[lsq].pre=nwq; 110 while(s[lsp].tranc[c]==lsq) 111 { 112 s[lsp].tranc[c]=nwq; 113 lsp=s[lsp].pre; 114 } 115 } 116 } 117 fin=nwp; 118 return ; 119 } 120 void ade(int f,int t) 121 { 122 cnt++; 123 e[cnt].twd=t; 124 e[cnt].lst=p[f].hd; 125 p[f].hd=cnt; 126 return ; 127 } 128 void Dfs(int x) 129 { 130 for(int i=p[x].hd;i;i=e[i].lst) 131 { 132 int to=e[i].twd; 133 Dfs(to); 134 p[x].wgt+=p[to].wgt; 135 p[x].endp=std::min(p[x].endp,p[to].endp); 136 } 137 if(p[x].wgt==1) 138 { 139 int minlen=s[s[x].pre].len+1; 140 int maxlen=s[x].len; 141 int endpos=p[x].endp; 142 T[0].update(1,n,endpos-maxlen+1,endpos-minlen+1,1,endpos+1); 143 T[1].update(1,n,endpos-minlen+1,endpos,1,minlen); 144 } 145 return ; 146 } 147 int main() 148 { 149 scanf("%s",tmp+1); 150 n=strlen(tmp+1); 151 for(int i=1;i<=n;i++) 152 Insert(tmp[i]-a,i); 153 for(int i=1;i<=siz;i++) 154 ade(s[i].pre,i); 155 T[0].res(); 156 T[1].res(); 157 Dfs(0); 158 for(int i=1;i<=n;i++) 159 { 160 int ans1,ans2; 161 ans1=T[0].query(1,n,i,1)-i; 162 ans2=T[1].query(1,n,i,1); 163 printf("%d\n",std::min(ans1,ans2)); 164 } 165 return 0; 166 }

BZOJ1396: 識別子串(後綴自動機,線段樹)