BZOJ2780(廣義後綴自動機,set啟發式合並)
阿新 • • 發佈:2019-03-31
哪些 ext space void n+1 iter == span c++
BZOJ2780(廣義後綴自動機,set啟發式合並)
題面
自己找去
HINT
就是給多個文本串,然後每次查詢的時候問你這個串在多少個文本串中出現過。因為多個文本串,那麽直接就往廣義後綴自動機上思考啊,我們在每個節點上開個set記錄一下在哪些文本串上出現過,最後查詢的時候就是看\(set[u].size()\)
啟發式合並
因為每個父親節點表示的子串都是兒子節點的後綴,所以兒子出現過的文本串,他爹也都出現過,那麽就從葉子節點向上啟發式合並就好了
#include<bits/stdc++.h> #include<set> using namespace std; const int maxn=200010; inline int read(){ int w=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ w=(w<<3)+(w<<1)+ch-48; ch=getchar(); } return w*f; } int n,m; bool debug; set<int> s[maxn]; set<int>::iterator it; struct SUFFIXAUTOMATON{ struct Node{ int len,fa; map<int,int> ch; }node[200010]; int lst,tot,root; inline void init(){ lst=tot=root=1;return; } inline void extend(int now,int id){ int p=lst;tot++;lst=tot;int np=tot; node[np].len=node[p].len+1;s[np].insert(id); while(p&&!node[p].ch[now]){ node[p].ch[now]=np; p=node[p].fa; } if(!p) node[np].fa=1; else{ int q=node[p].ch[now]; if(node[q].len==node[p].len+1){ node[np].fa=q; } else{ int nq=++tot;node[nq]=node[q]; node[nq].len=node[p].len+1; node[q].fa=nq;node[np].fa=nq; while(p&&node[p].ch[now]==q){ node[p].ch[now]=nq; p=node[p].fa; } } } } }SAM; char ch[500010]; int head[200010],cnt; struct Edge{ int from,to,next; }edge[1200010]; inline void addedge(int u,int v){ cnt++; edge[cnt].from=u; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; } int sum[200010]; inline void dfs(int u){ if(debug)cout<<u<<endl; for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to;dfs(v); if(s[u].size()<s[v].size()) swap(s[u],s[v]); for(it=s[v].begin();it!=s[v].end();it++){ s[u].insert(*it); } } sum[u]=s[u].size();return; } int main(){ n=read();m=read();SAM.init(); for(int i=1;i<=n;i++){ scanf("%s",ch);int len=strlen(ch); for(int j=0;j<len;j++){ SAM.extend(ch[j]-'a'+1,i); } SAM.lst=1; } for(int i=2;i<=SAM.tot;i++){ addedge(SAM.node[i].fa,i); } dfs(1); for(int i=1;i<=m;i++){ scanf("%s",ch);int len=strlen(ch);int u=SAM.root; for(int j=0;j<len;j++){ u=SAM.node[u].ch[ch[j]-'a'+1]; } printf("%d\n",sum[u]); } return 0; }
BZOJ2780(廣義後綴自動機,set啟發式合並)