loj #6070. 「2017 山東一輪集訓 Day4」基因
阿新 • • 發佈:2018-12-05
迴文自動機好題啊!
解法一
每$\sqrt n \(分一塊 每塊建迴文自動機到字串末尾。 順便開三個\)\sqrt n *n \(的陣列記下預處理答案,迴文自動機頭指標,和每個節點第一次出現的右端點 詢問的時候迴文自動機前端新增,算出答案。 貌似不能寫均攤複雜度的迴文自動機,只能寫單次複雜度有證明的。 設\)T\(為字符集大小 時間複雜度\)O(Tn \sqrt n)$
#include <bits/stdc++.h> using namespace std; const int N=100010,D=320; int pre[D][N],preworkans[D][N],firstappear[D][N],vis[N]; struct pam{ struct pamnode{ int len,fa,anc[26],trans[26]; }T[N]; int tot,fi,la; pam(){ T[1].len=-1; T[0].fa=1; for (int j=0; j<26; ++j) T[0].anc[j]=1; tot=1; fi=0; la=0; } void pushback(char *s,int l,int r){ int c=s[r]-'a'; if (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].anc[c]; if (!T[la].trans[c]){ int q=++tot,k=T[la].fa; T[q].len=T[la].len+2; if (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) T[q].fa=T[T[k].anc[c]].trans[c]; else T[q].fa=T[k].trans[c]; memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc)); T[q].anc[s[r-T[T[q].fa].len]-'a']=T[q].fa; T[la].trans[c]=q; } la=T[la].trans[c]; if (T[la].len==r-l+1) fi=la; } void pushfront(char *s,int l,int r){ int c=s[l]-'a'; if (l+T[fi].len+1>r||s[l]!=s[l+T[fi].len+1]) fi=T[fi].anc[c]; if (!T[fi].trans[c]){ int q=++tot,k=T[fi].fa; T[q].len=T[fi].len+2; if (l+T[k].len+1>r||s[l]!=s[l+T[k].len+1]) T[q].fa=T[T[k].anc[c]].trans[c]; else T[q].fa=T[k].trans[c]; memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc)); T[q].anc[s[l+T[T[q].fa].len]-'a']=T[q].fa; T[fi].trans[c]=q; } fi=T[fi].trans[c]; if (T[fi].len==r-l+1) la=fi; } }A; int ty,n,q,S,clk,ans; char s[N]; int main(){ scanf("%d%d%d%s",&ty,&n,&q,s+1); S=sqrt(n); for (int i=0; i*S+1<=n; ++i){ A.fi=A.la=0; ++clk; for (int j=i*S+1; j<=n; ++j){ A.pushback(s,i*S+1,j); preworkans[i][j]=preworkans[i][j-1]; if (vis[A.la]<clk){ vis[A.la]=clk; firstappear[i][A.la]=j; ++preworkans[i][j]; } pre[i][j]=A.fi; } } while (q--){ int l,r; scanf("%d%d",&l,&r); l^=(ty*ans); r^=(ty*ans); ++clk; if ((l-1)/S==(r-1)/S){ A.fi=A.la=0; ans=0; for (int i=l; i<=r; ++i){ A.pushback(s,l,i); if (vis[A.la]<clk){ vis[A.la]=clk; ++ans; } } } else{ int L=(l-1)/S+1-(l%S==1); A.fi=pre[L][r]; ans=preworkans[L][r]; for (int i=L*S; i>=l; --i){ A.pushfront(s,i,r); if (vis[A.fi]<clk){ vis[A.fi]=clk; if (firstappear[L][A.fi]>r||firstappear[L][A.fi]==0) ++ans; } } } cout<<ans<<'\n'; } }
解法2
記迴文自動機上一個節點的串長為\(len(x)\),父節點為\(fa(x)\),則對於迴文樹上一條鏈,從葉子到根,\(len(x)-len(fa(x))\)遞減,且只有\(log\)種取值,也就是說,可以分成\(log\)個等差數列。
主席樹維護掃描右端點時左端點的答案,一個等差數列就是一個區間加。
時間複雜度\(O(nlog^2(n))\)
#include <bits/stdc++.h> using namespace std; #define debug(x) cerr<<#x<<":"<<x<<endl const int N=100010; const int P=270010; const int D=17*17*N; struct zkw{ int u,st[P]; void init(int len){ for (u=1; u<len; u<<=1); --u; } void mark(int s,int t){ //cerr<<"Mark"<<s<<" "<<t<<endl; for (s+=u; s; s>>=1) st[s]=max(st[s],t); } int ask(int s,int t){ //cerr<<"ask"<<s<<" "<<t<<endl; int ret=0; for (s+=u-1,t+=u+1; s^t^1; s>>=1,t>>=1){ if (~s&1) ret=max(ret,st[s^1]); if (t&1) ret=max(ret,st[t^1]); } //debug(ret); return ret; } }seg1; struct president{ int ll,rr,tot; struct presidentnode{ int l,r,v; }T[D]; void add(int &ind,int l,int r){ /*if (l!=13||r!=12){ debug(l); debug(r); debug(tot); debug(ll); debug(rr); }*/ T[++tot]=T[ind]; ind=tot; //cerr<<"CC"<<endl; if (ll<=l&&r<=rr) return void(++T[ind].v); int mid=(l+r)>>1; if (ll<=mid) add(T[ind].l,l,mid); if (mid<rr) add(T[ind].r,mid+1,r); } int ask(int ind,int l,int r){ if (l==r) return T[ind].v; int mid=(l+r)>>1; return (ll<=mid?ask(T[ind].l,l,mid):ask(T[ind].r,mid+1,r))+T[ind].v; } }seg2; struct pam{ vector<int> g[N]; struct pamnode{ int fa,len,d,df,trans[26]; }T[N]; int la,tot,dfn[N],clk,lst[N]; pam(){ T[1].len=-1; T[0].fa=1; T[0].d=-1; tot=1; la=0; } int pushback(char *s,int l,int r){ int c=s[r]-'a'; while (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].fa; if (!T[la].trans[c]){ int q=++tot,k=T[la].fa; T[q].len=T[la].len+2; while (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) k=T[k].fa; T[q].fa=T[k].trans[c]; T[la].trans[c]=q; T[q].d=(T[q].fa?T[q].len-T[T[q].fa].len:0); T[q].df=(T[q].d==T[T[q].fa].d?T[T[q].fa].df:q); } return la=T[la].trans[c]; } void dfs(int x){ //debug(x); debug(fa); dfn[x]=clk++; for (auto i:g[x]) dfs(i); lst[x]=clk-1; } void prework(){ for (int i=tot; i>1; --i) g[T[i].fa].push_back(i); dfs(0); } }A; int ty,n,q,ans,rt[N],rec[N]; char s[N]; void build(){ //for (int i=1; i<=A.tot; ++i) debug(A.dfn[i]); seg1.init(A.tot); for (int i=1; i<=n; ++i){ rt[i]=rt[i-1]; int x=rec[i]; while (x>1){ seg2.ll=max(seg1.ask(A.dfn[x],A.lst[x])-A.T[x].len+2,1); seg2.rr=i-A.T[A.T[x].df].len+1; //cerr<<"plus"<<i<<" "<<seg2.ll<<" "<<seg2.rr<<" "<<A.T[x].df<<" "<<A.T[x].len<<endl; seg2.add(rt[i],1,n); x=A.T[A.T[x].df].fa; } seg1.mark(A.dfn[rec[i]],i); } } int main(){ scanf("%d%d%d%s",&ty,&n,&q,s+1); for (int i=1; i<=n; ++i) rec[i]=A.pushback(s,1,i)/*,debug(rec[i]),debug(A.T[rec[i]].fa)*/; A.prework(); build(); while (q--){ int l,r; scanf("%d%d",&l,&r); l^=(ty*ans); r^=(ty*ans); seg2.ll=l; cout<<(ans=seg2.ask(rt[r],1,n))<<'\n'; } }