Codeforces 547E. Mike and Friends 題解
阿新 • • 發佈:2020-07-26
題目大意:
- 給定\(n\)個字串\(s_1,s_2,\dots,s_n\)
- \(q\)次詢問\(s_k\)在\(s_{l,\dots,r}\)中出現了多少次。
題解:考慮 AC 自動機的 fail 樹,將每一個串插入到 AC 自動機中,然後建出 fail 樹,一個串出現的次數就是它的 fail 樹的子樹大小,因為這一道題不是全域性查詢,所以講每一個詢問差分成\(l-1,r\)兩個詢問,排序,每一次對於當前串的鏈全部加一,然後直接統計即可。
查詢子樹和用 dfs 序加上樹狀陣列即可。
程式碼:
#include <queue> #include <cstdio> using namespace std; int abs(int a){ return a<0?-a:a; } const int Maxn=200000; const int Maxq=500000; int n,q; char s[Maxn+5]; int pos[Maxn+5]; int dfn[Maxn+5],dfn_tot; vector<int> edge[Maxn+5]; int sz[Maxn+5]; int k[Maxq+5]; struct Node{ int ch[26]; int fail,fa; }node[Maxn+5]; vector<int> que[Maxn+5]; int id_tot=1; int insert(int n){ int root=1; for(int i=1;i<=n;i++){ if(node[root].ch[s[i]-'a']==0){ node[root].ch[s[i]-'a']=++id_tot; node[id_tot].fa=root; } root=node[root].ch[s[i]-'a']; } return root; } void dfs(int u){ dfn[u]=++dfn_tot; sz[u]=1; for(int i=0;i<(int)edge[u].size();i++){ int v=edge[u][i]; dfs(v); sz[u]+=sz[v]; } } void build(){ queue<int> q; for(int i=0;i<26;i++){ if(node[1].ch[i]){ node[node[1].ch[i]].fail=1; q.push(node[1].ch[i]); } else{ node[1].ch[i]=1; } } while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<26;i++){ if(node[u].ch[i]){ node[node[u].ch[i]].fail=node[node[u].fail].ch[i]; q.push(node[u].ch[i]); } else{ node[u].ch[i]=node[node[u].fail].ch[i]; } } } for(int i=2;i<=id_tot;i++){ edge[node[i].fail].push_back(i); } dfs(1); } int f[Maxn+5]; void add(int x,int a){ for(int i=x;i<=id_tot;i+=(i&(-i))){ f[i]+=a; } } int query(int x){ int ans=0; for(int i=x;i>0;i-=(i&(-i))){ ans+=f[i]; } return ans; } int ans[Maxq+5]; int main(){ scanf("%d%d",&n,&q); for(int i=1;i<=n;i++){ scanf("%s",s+1); int len=0; while(s[++len]!='\0'); len--; pos[i]=insert(len); } build(); for(int i=1;i<=q;i++){ int l,r; scanf("%d%d%d",&l,&r,&k[i]); if(l>1){ que[l-1].push_back(-i); } que[r].push_back(i); } for(int i=1;i<=n;i++){ int root=pos[i]; while(root!=1){ add(dfn[root],1); root=node[root].fa; } for(int j=0;j<(int)que[i].size();j++){ int id=abs(que[i][j]); int x=pos[k[id]]; if(que[i][j]>0){ ans[id]+=query(dfn[x]+sz[x]-1)-query(dfn[x]-1); } else{ ans[id]-=query(dfn[x]+sz[x]-1)-query(dfn[x]-1); } } } for(int i=1;i<=q;i++){ printf("%d\n",ans[i]); } return 0; }