日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】

發(fā)布時(shí)間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

傳送門(mén)

題意:給定字符串SSS,求一堆字符串s1,s2,s3,...,sks_1,s_2,s_3,...,s_ks1?,s2?,s3?,...,sk?,滿(mǎn)足s1s_1s1?SSS的子串,且sis_isi?si?1s_{i-1}si?1?中至少出現(xiàn)兩次,最大化kkk

∣S∣≤200000|S| \leq 200000S200000

神仙題

顯然建出后綴自動(dòng)機(jī)然后在failfailfail樹(shù)上亂搞

但很快發(fā)現(xiàn)不好描述出現(xiàn)兩次

于是考慮回歸到后綴自動(dòng)機(jī)的本質(zhì):endposendposendpos

對(duì)于子串S,TS,TS,T,如果SSSTTT中出現(xiàn)兩次

那么在某一個(gè)TTT的覆蓋范圍里,SSS出現(xiàn)了兩次

換句話(huà)說(shuō),對(duì)于TTT的任意一個(gè)endposendposendpos,記為pos[T]pos[T]pos[T],其覆蓋范圍為[pos[T]?len[T],pos[T]][pos[T]-len[T],pos[T]][pos[T]?len[T],pos[T]]

這段里出現(xiàn)了兩個(gè)[pos[S]?len[S],pos[S]][pos[S]-len[S],pos[S]][pos[S]?len[S],pos[S]]

[pos[T]?len[T]+len[S],pos[T]][pos[T]-len[T]+len[S],pos[T]][pos[T]?len[T]+len[S],pos[T]]中有至少兩個(gè)SSSendposendposendpos

于是可以用可持久化線(xiàn)段樹(shù)來(lái)維護(hù),由于某個(gè)點(diǎn)的endposendposendpos等于其failfailfail樹(shù)的兒子的endposendposendpos的并集,寫(xiě)個(gè)線(xiàn)段樹(shù)合并即可。

查詢(xún)的時(shí)候由于是單調(diào)的,用倍增查最下面的滿(mǎn)足條件的祖先。

復(fù)雜度O(nlog2n)O(nlog^2n)O(nlog2n)

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #define MAXN 400005 using namespace std; namespace SGT {int ch[MAXN<<5][2],sum[MAXN<<5],cnt;inline int copy(const int& x){int ans=++cnt;ch[ans][0]=ch[x][0],ch[ans][1]=ch[x][1],sum[ans]=sum[x];return ans;}void insert(int& x,int l,int r,int k){++sum[x=++cnt];if (l==r) return;int mid=(l+r)>>1;if (k<=mid) insert(ch[x][0],l,mid,k);else insert(ch[x][1],mid+1,r,k);}int merge(int x,int y){if (!x||!y) return x|y;int p=copy(x);sum[p]+=sum[y];ch[p][0]=merge(ch[p][0],ch[y][0]);ch[p][1]=merge(ch[p][1],ch[y][1]);return p;}int getpos(int x,int l,int r){if (l==r) return l;int mid=(l+r)>>1;if (sum[ch[x][0]]) return getpos(ch[x][0],l,mid);else return getpos(ch[x][1],mid+1,r);}int query(int x,int l,int r,int ql,int qr){if (ql<=l&&r<=qr) return sum[x];if (r<ql||qr<l) return 0;int mid=(l+r)>>1;return query(ch[x][0],l,mid,ql,qr)+query(ch[x][1],mid+1,r,ql,qr);} } int n; char s[MAXN]; namespace SAM {int ch[MAXN][26],fa[MAXN],len[MAXN],pos[MAXN],tot=1,las=1;int rt[MAXN];void insert(int c){int cur=++tot,p=las;len[cur]=len[p]+1;las=cur;for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;if (!p) return (void)(fa[cur]=1);int q=ch[p][c];if (len[q]==len[p]+1) fa[cur]=q;else{int _q=++tot;len[_q]=len[p]+1;fa[_q]=fa[q];fa[q]=fa[cur]=_q;memcpy(ch[_q],ch[q],sizeof(ch[q]));for(;ch[p][c]==q;p=fa[p]) ch[p][c]=_q;}}int jump[MAXN][20];int a[MAXN],c[MAXN],f[MAXN]={-1};inline bool check(int x,int y){return len[x]==0||SGT::query(rt[x],1,n,pos[y]-len[y]+len[x],pos[y])>=2;}int build(){for (int i=1;i<=n;i++) insert(s[i]-'a'),SGT::insert(rt[las],1,n,i);for (int i=1;i<=tot;i++) ++c[len[i]];for (int i=1;i<=n;i++) c[i]+=c[i-1];for (int i=tot;i>=1;i--) a[c[len[i]]--]=i;for (int i=tot;i>=1;i--){pos[a[i]]=SGT::getpos(rt[a[i]],1,n);rt[fa[a[i]]]=SGT::merge(rt[fa[a[i]]],rt[a[i]]);}for (int i=1;i<=tot;i++){jump[a[i]][0]=fa[a[i]];for (int k=1;k<20;k++) jump[a[i]][k]=jump[jump[a[i]][k-1]][k-1];int anc=a[i];for (int k=19;k>=0;k--) if (!check(jump[anc][k],a[i])) anc=jump[anc][k];anc=fa[anc];f[a[i]]=f[anc]+1;}int mx=0;for (int i=1;i<=tot;i++) mx=max(mx,f[i]);return mx;} } int main() {scanf("%d",&n);scanf("%s",s+1);printf("%d\n",SAM::build());return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。