[BZOJ2434][NOI2011]阿狸的打字机(AC自动机+树状数组)

来源:互联网 发布:无人机编程教材 编辑:程序博客网 时间:2024/05/16 07:52

题目描述

我是超链接

题解:

trie树可以边扫边建;存一下father因为B操作是需要跳回去的。 
建好fail指针之后,每次询问其实就是判断y这个单词里的节点有多少个指针指向了x。其实可以逆向思维,就是求fail树中x的子树有哪些是在y这个单词中-----“fail树的神奇性质”
求出fail树的dfs序,夹在in和out之间的是整棵树,为了避免加重,从1-in。 
离线之后按照y排序,我们可以边扫大字符串边进行维护,打出新的字母就加,删除就减,遇到p说明到了一个新的字符串,那么就可以查询了。 
维护用树状数组

代码

#include <cstdio>#include <algorithm>#include <cstring>#include <iostream>#include <queue>#define N 100005#define M N*2using namespace std;struct hh{int r,c,id;}a[N+5];int v[M],tot=0,tt=0,point[N],next[M],as=0,in[N],out[N],l,fa[N],ch[N][30],num=0,end[N],fail[N],n,c[N],ans[N];char st[N];int cmp(hh a,hh b){return a.c<b.c;}void addline(int x,int y){++tt; next[tt]=point[x]; point[x]=tt; v[tt]=y;++tt; next[tt]=point[y]; point[y]=tt; v[tt]=x;}void trie(){int now=0,i;for (i=0;i<l;i++)  if (st[i]>='a' && st[i]<='z')  {  int x=st[i]-'a';  if (!ch[now][x]) ch[now][x]=++tot;  fa[ch[now][x]]=now;  now=ch[now][x];  }  else   if (st[i]=='P')     end[++num]=now;  else    now=fa[now];}void sp(){int i;queue <int> q;for (i=0;i<26;i++)  if (ch[0][i])   {  q.push(ch[0][i]); addline(0,ch[0][i]);  }while (!q.empty()){int now=q.front();q.pop();for (i=0;i<26;i++){if (!ch[now][i]){ch[now][i]=ch[fail[now]][i];continue;}fail[ch[now][i]]=ch[fail[now]][i];addline(fail[ch[now][i]],ch[now][i]);q.push(ch[now][i]);}}}void dfs(int now,int fa){int i;in[now]=++as;for (i=point[now];i;i=next[i])  if (v[i]!=fa)    dfs(v[i],now);out[now]=as;}void add(int loc,int value){for (int i=loc;i<=as;i+=i&(-i))    c[i]+=value;}int qurry(int loc){int ans=0;for (int i=loc;i>0;i-=i&(-i))  ans+=c[i];return ans;}int main(){int i;scanf("%s",st);l=strlen(st);int nn=0,e=1;trie();sp();scanf("%d",&n);for (i=1;i<=n;i++){scanf("%d%d",&a[i].r,&a[i].c);a[i].id=i;}dfs(0,-1);  sort(a+1,a+n+1,cmp);int now=0;for (i=0;i<l;i++)  if (st[i]>='a' && st[i]<='z')  {  int x=st[i]-'a';  now=ch[now][x];  add(in[now],1);}  else    if (st[i]=='P')    {    nn++;    int j=0;    if (nn==a[e].c)    {    while (nn==a[e+j].c)    {    int ans1=qurry(in[end[a[e+j].r]]-1);        int ans2=qurry(out[end[a[e+j].r]]);        ans[a[e+j].id]=ans2-ans1;        j++;}    e=e+j;}}  else  {  add(in[now],-1); now=fa[now];   }for (i=1;i<=n;i++)  printf("%d\n",ans[i]);}



0 0
原创粉丝点击