1. 程式人生 > >AC自動機 NOI2011 阿狸的打字機

AC自動機 NOI2011 阿狸的打字機

AC自動機上 根據fail指標 暴力跳有40分
所以我們可以考慮這麼做
對於x和y串 顯然若y上的每個節點可以通過fail跳到x的尾節點 那答案就是個數和
在y節點上打標記,
然後我們把fail指標反向 我們可以發現變成了求x尾節點的子樹和
子樹和可以通過dfs對映到陣列上記錄一下每個節點dfs訪問到的時間和離開的時間 可以表示這棵樹的範圍
然後用樹狀陣列維護我們的求和過程

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&(-x))
#define mp(a,b) make_pair(a,b)
#define pb push_back typedef pair<int,int> Pair; vector<int> G[102000]; int ans[102000]; int in[1020000]; int out[1020000]; int tree[102000]; int m; int cnt; //樹狀陣列不解釋 int getsum(int x){ int ret = 0; for(int i=x;i;i-=lowbit(i)){ ret+=tree[i]; } return ret; } void update(int x,int val){ for(int i=x;i<=
cnt;i+=lowbit(i)){ tree[i]+=val; } } //求出每個節點的DFS序 void dfs(int x){ in[x]=++cnt; for(int i=0;i<G[x].size();++i){ int to = G[x][i]; dfs(to); } out[x]=cnt; } struct node{ int x,y,id; }q[102000]; struct Trie{ int nxt[100010][26],fail[100010],end[100010],fa[101000],f[102000]; string s; int root,L,n; int newnode
(){ for(int i=0;i<26;++i){ nxt[L][i]=-1; } end[L++]=0; return L-1; } void init(){ L=0; root=newnode(); } void insert(){ int now = 0; cin>>s; int len = s.size(); for(int i=0;i<len;++i){ if(s[i]=='P') f[++n] = now;//新增一串 記錄末節點位置 else if(s[i]=='B') now = fa[now];//跳到父親節點 else{ if(nxt[now][s[i]-'a']==-1){ nxt[now][s[i]-'a']=newnode(); } fa[nxt[now][s[i]-'a']] = now;//記錄父親節點 now = nxt[now][s[i]-'a']; } } } void build(){ queue<int> Q; fail[root] = root; for(int i=0;i<26;++i){ if(nxt[root][i] == -1){ nxt[root][i] = root; } else{ fail[nxt[root][i]] = root; Q.push(nxt[root][i]); } } while(!Q.empty()){ int now = Q.front(); Q.pop(); for(int i=0;i<26;++i){ if(nxt[now][i]==-1){ nxt[now][i] = nxt[fail[now]][i]; } else{ fail[nxt[now][i]] = nxt[fail[now]][i]; Q.push(nxt[now][i]); } } } //每個fail指標反向 for(int i=1;i<=L;i++){ G[fail[i]].pb(i); } } void solve(){ int now = 0; int id = 1; n=0; for(int i=0;i<s.size();++i){ if(s[i]=='P'){ n++; while(q[id].y==n&&id<=m){//始終是第二個串 可以省去很多不必要的時間 int t = f[q[id].x];//第一個串的終點 ans[q[id].id]=getsum(out[t])-getsum(in[t]-1); ++id; } } else if(s[i]=='B'){ update(in[now],-1); now = fa[now]; } else{ now = nxt[now][s[i]-'a']; update(in[now],1); } } } }ac; bool cmp(node a,node b){ return a.y<b.y; } int main(){ ac.init(); ac.insert(); ac.build(); dfs(0); cin>>m; for(int i=1;i<=m;++i){ cin>>q[i].x>>q[i].y; q[i].id = i; } sort(q+1,q+1+m,cmp); ac.solve(); for(int i=1;i<=m;++i) cout<<ans[i]<<endl; return 0; }