[bzoj3277]串 "廣義字尾自動機
阿新 • • 發佈:2018-12-13
[bzoj3277]串
廣義字尾自動機板子題
廣義字尾自動機的建圖方法大概就是在trie上按bfs序來建圖,這裡的last節點應該是trie上父親的last節點
然後這裡按題目要求記right為在至少k個串走過的方案,具體建法就是先把每個串跑一遍然後在parent樹上更新所有父親節點的答案,注意不要判重。然後掃一遍所有節點如果right>k就把val設成maxlen-minlen(minlen=parent樹上的fa->maxlen)
最後用父親節點更新子節點就行了。
- 程式碼
#include<bits/stdc++.h> using namespace std; const int N=2e5+5,SZ=26; int n,k; char ch[N]; int l[N],r[N],tot; struct SuffixAutomaton { struct node{ int ch[SZ],fa; int len,right; int pre; }t[N]; int root,cnt; inline int newnode(int _len=0){ t[++cnt].len=_len; return cnt; } inline void init(){//"初始化 root=newnode(0); } inline int ins(int c,int last)//"c=(char)-'a'; { int nq=newnode(t[last].len+1),q=last; for(;q&&!t[q].ch[c];q=t[q].fa)t[q].ch[c]=nq; if(q==0) t[nq].fa=root; else if(t[t[q].ch[c]].len==t[q].len+1)t[nq].fa=t[q].ch[c]; else{ int np=newnode(t[q].len+1),p=t[q].ch[c]; memcpy(t[np].ch,t[p].ch,sizeof(t[p].ch)); t[np].fa=t[p].fa; t[p].fa=t[nq].fa=np; for(;q&&t[q].ch[c]==p;q=t[q].fa)t[q].ch[c]=np; } return nq; } int topo[N],buc[N]; inline void toposet(){ int mx=0; for(int i=1;i<=cnt;i++)buc[t[i].len]++,mx=max(mx,t[i].len); for(int i=1;i<=mx;i++)buc[i]+=buc[i-1]; for(int i=1;i<=cnt;i++)topo[buc[t[i].len]--]=i; } inline void cal_right() { toposet(); for(int i=1;i<=cnt;i++){ int cur=topo[i]; t[cur].right+=t[t[cur].fa].right; } } inline void preset(){ for(int i=1;i<=cnt;i++){ if(t[i].right<k)t[i].right=0; else t[i].right=t[i].len-t[t[i].fa].len; } cal_right(); } }sam; typedef pair<int,int> pii; struct trietree{ struct node{ int ch[SZ]; }t[N]; int cnt; inline void ins(char s[]){ int len=strlen(s+1); int cur=0; for(int i=1;i<=len;i++){ int c=s[i]-'a'; if(t[cur].ch[c])cur=t[cur].ch[c]; else{ cnt++;t[cur].ch[c]=cnt; cur=t[cur].ch[c]; } } } inline void bfs(){ queue<pii>q; q.push(pii(0,sam.root)); while(!q.empty()){ pii cur=q.front();q.pop(); int u=cur.first; for(int i=0;i<SZ;i++)if(t[u].ch[i]){ int tmp=sam.ins(i,cur.second); q.push(pii(t[u].ch[i],tmp)); } } } }trie; char str[N]; int main() { sam.init(); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%s",str+1); trie.ins(str); int len=strlen(str+1); l[i]=tot+1; for(int j=1;j<=len;j++) ch[++tot]=str[j]; r[i]=tot; } trie.bfs(); for(int i=1;i<=n;i++){ int now=sam.root; for(int j=l[i];j<=r[i];j++){ int c=ch[j]-'a'; now=sam.t[now].ch[c]; int tmp=now; for(;tmp!=sam.root&&sam.t[tmp].pre!=i;tmp=sam.t[tmp].fa) sam.t[tmp].pre=i,sam.t[tmp].right++; } } sam.preset(); for(int i=1;i<=n;i++){ int ans=0; int now=sam.root; for(int j=l[i];j<=r[i];j++){ int c=ch[j]-'a'; for(;now&&!sam.t[now].ch[c];now=sam.t[now].fa); if(now){ now=sam.t[now].ch[c]; ans+=sam.t[now].right; }else now=sam.root; } printf("%d ",ans); } return 0; }