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
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 ",std::min(ans1,ans2)); 164 } 165 return 0; 166 }