orzzw的超短写法.
终于明白fail树是什么意思了-.-
写完交到gfoj无故re,好在cv和bz上都过了.
#include <cstdio>
using namespace std;
const int N=100050;
struct edge {
int u,v; edge *nxt;
edge (int u,int v,edge *pre): u(u),v(v){nxt=pre;}
};
edge *he[N],*qe[N];
int ans[N],ent[N],out[N],cnt;
int fa[N],fail[N],tot;
int id[N],to[N][26],cot;
int q[N];
struct xdt {
#define mid ((l+r)>>1)
int a[8*N];
void add(int t,int l,int r,int x,int k) {
a[t]+=k;
if (l==r) return ;
if (x<=mid) add(t*2,l,mid,x,k); else add(t*2+1,mid+1,r,x,k);
}
int ask(int t,int l,int r,int x,int y) {
if (x<=l && r<=y) return a[t];
int ans=0;
if (x<=mid) ans+=ask(t*2,l,mid,x,y);
if (y>mid) ans+=ask(t*2+1,mid+1,r,x,y);
return ans;
}
}xdt;
void dfs(int u) {
ent[u]=++cnt;
for (edge *i=he[u];i;i=i->nxt) dfs(i->v);
out[u]=++cnt;
}
void DFS(int u) {
xdt.add(1,1,cnt,ent[u],1);
for (edge *i=qe[u];i;i=i->nxt)
ans[i->u]=xdt.ask(1,1,cnt,ent[i->v],out[i->v]);
for (int j=0;j<26;j++) if (to[u][j]) DFS(to[u][j]);
xdt.add(1,1,cnt,ent[u],-1);
}
int main() {
#define nxt to[nw][ch-'a']
int i,j,n,x,y,l,r,nw; char ch;
while ((ch=getchar())!='P' && ch!='B' && (ch<'a'||ch>'z')) ;
for (i=0;i<26;i++) to[0][i]=1;
for (tot=nw=1;ch=='P' || ch=='B' || (ch>='a' && ch<='z');ch=getchar()) {
if (ch=='P') id[++cot]=nw; else
if (ch=='B') nw=fa[nw]; else
fa[nxt?nxt:nxt=++tot]=nw,nw=nxt;
}
for (l=r=q[1]=1;l<=r;l++)
for (nw=q[l],i=0;i<26;i++) if (to[nw][i]) {
for (j=fail[nw];!to[j][i];j=fail[j]) ;
fail[q[++r]=to[nw][i]]=to[j][i];
}
for (i=1;i<=tot;i++) he[fail[i]]=new edge(fail[i],i,he[fail[i]]);
for (scanf("%d",&n),i=1;i<=n;i++) {
scanf("%d%d",&x,&y); x=id[x],y=id[y];
qe[y]=new edge(i,x,qe[y]);
}
dfs(1);
DFS(1);
for (i=1;i<=n;i++) printf("%d\n",ans[i]);
}