ac自动机,bit,dfs序。
本文所有的stl都是因为自己懒得实现。
首先x在y里面出现,就意味y节点可以顺着fail回去。
反向建出一个fail数,然后搞出dfs序列。找出x对应的区间有多少个y。
再用离线操作,把每个y需要计算的x事先保存下来。
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<vector> using namespace std; const int maxn = 100000 + 10; char s[maxn]; int a[maxn][26]; int g[maxn],v[maxn],next[maxn],eid; int pos[maxn],cnt; int fa[maxn],fail[maxn],L[maxn],R[maxn],query[maxn][3]; int m,n,u,dfn,vid; vector<int> Q[maxn]; queue<int> q; struct BIT { int a[maxn<<1],n; int lowbit(int x) { return (x & -x); } void add(int x,int d) { //printf("c %d %d ",x,d); for(;x<=n;x+=lowbit(x)) a[x]+=d; //printf("c"); } int query(int x) { int res=0; for(;x;x-=lowbit(x)) res+=a[x]; return res; } void init(int _n) { n=_n; } }bit; void addedge(int a,int b) { v[eid]=b; next[eid]=g[a]; g[a]=eid++; } void dfs(int u) { L[u]=++dfn; for(int i=g[u];~i;i=next[i]) dfs(v[i]); R[u]=dfn; } void get_trie() { for(int i=0;i<26;i++) a[0][i]=1; int p=1,c;vid=1; for(int i=0;i<n;i++) { //printf("f[%d] = %d ",i,p); if(s[i]=='P') pos[++cnt]=p; else if(s[i]=='B') p=fa[p]; else { c=s[i]-'a'; if(!a[p][c]) a[p][c]=++vid,fa[vid]=p; p=a[p][c]; } //printf("f[%d] = %d ",i,p); } } void debug(int p) { } void get_fail() { fail[1]=0; q.push(1); while(!q.empty()) { u=q.front();q.pop(); for(int k=0,p;k<26;k++) if(a[u][k]) { for(p=fail[u];p&&!a[p][k];p=fail[p]); fail[a[u][k]]=a[p][k]; q.push(a[u][k]); } } } void get_tree() { for(int i=1;i<=vid;i++) addedge(fail[i],i); dfs(1); } void build() { memset(g,-1,sizeof(g)); scanf("%s",s);n=strlen(s); get_trie(); //debug(1); get_fail(); get_tree(); scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d %d",&query[i][0],&query[i][1]); query[i][0]=pos[query[i][0]]; query[i][1]=pos[query[i][1]]; Q[query[i][1]].push_back(i); } } void solve() { bit.init(n<<1); int p=1; for(int i=0;i<n;i++) { //printf("s[i]=%c ",s[i]); if(s[i]=='P') for(int j=0;j<Q[p].size();j++) query[Q[p][j]][2]=bit.query(R[query[Q[p][j]][0]])-bit.query(L[query[Q[p][j]][0]]-1); else if(s[i]=='B') bit.add(L[p],-1),p=fa[p]; else p=a[p][s[i]-'a'],bit.add(L[p],1); //printf(" %d ",i); } for(int i=1;i<=m;i++) printf("%d ",query[i][2]); } int main() { build(); solve(); return 0; }