[NOI 2011][BZOJ 2434] 阿狸的打字机

传送门

AC自动机 + 树状数组

建成AC自动机后,设end[i]为第i个串的末尾在Trie树上的节点。

可以发现,对于一个询问(x,y),ans等于Trie树上root到end[y]这条链上fail指针指向end[x]的节点数,我们把这些点记为特殊点

因为Trie树上每个节点fail指针仅指向一个值,

因此可以将fail指针反转构建一棵树,以下称为fail树。

于此答案可以等价于在fail树上以end[x]为根的子树中存在的特殊点个数。

 

然而这样暴力做还是过不了。于是需要一些优化。

 

可以知道将一个树的节点按dfs序排列后,

树的任意一颗子树的节点在序列中都是连续的一段区间。

我们把特殊的点记为1,非特殊点记为0,

于是求某子树上的特殊点个数可以转化成求某区间的和,

于是就可以用树状数组来优化了。(线段树应该也可以吧,不过似乎会比较麻烦)。

 

代码:

  1 #include<cstdio>
  2 #include<queue>
  3 #include<algorithm>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 
  8 #define N ((1<<17)-1)
  9 #define M ((1<<17)-1)
 10 #define lowbit(x) ((x)&(-(x)))
 11 
 12 queue<int>q;
 13 char s[N];
 14 int end[N],n;
 15 
 16 struct ACA
 17 {
 18     int cnt;
 19     int fa[N],son[N][26],fail[N];
 20     void get_trie()
 21     {
 22         cnt=1;
 23         int i,now=1,v,p=0;
 24         for (i=0;i<n;i++)
 25             switch(s[i])
 26             {
 27                 case 'P':{end[++p]=now;break;}
 28                 case 'B':{now=fa[now];break;}
 29                 default:
 30                 {
 31                     v=s[i]-'a';
 32                     if (!son[now][v])
 33                     {
 34                         son[now][v]=++cnt;
 35                         fa[cnt]=now;    
 36                     }
 37                     now=son[now][v];
 38                 }
 39             }
 40         for (i=0;i<26;i++) son[0][i]=1; 
 41     }
 42     void get_fail()
 43     {
 44         int i,j,x;
 45         q.push(1);
 46         while (!q.empty())
 47         {
 48             x=q.front(),q.pop();
 49             for (i=0;i<26;i++)
 50                 if (son[x][i])
 51                 {
 52                     for (j=fail[x];j&&!son[j][i];j=fail[j]);
 53                     fail[son[x][i]]=son[j][i];
 54                     q.push(son[x][i]);
 55                 }
 56         }
 57     }
 58 }aca;
 59 
 60 struct BIT
 61 {
 62     int arr[N],l[N],r[N];
 63     int sum(int i)
 64     {
 65         int re=0;
 66         while (i)
 67         {re+=arr[i];i-=lowbit(i);}
 68         return re;
 69     }
 70     void add(int i,int k)
 71     {
 72         while (i<=aca.cnt)
 73         {arr[i]+=k;i+=lowbit(i);}    
 74     }
 75 }bit;
 76 
 77 
 78 struct Tree
 79 {
 80     vector<vector<int> >son;
 81     void addedge(int u,int v)
 82     {
 83         son[u].push_back(v);
 84     }
 85     void build()
 86     {
 87         son.resize(aca.cnt+1);
 88         for (int i=2;i<=aca.cnt;i++)
 89         addedge(aca.fail[i],i);
 90     }
 91     void dfs_order(int x,int &k)
 92     {
 93         bit.l[x]=bit.r[x]=k++;
 94         for (int i=0;i<son[x].size();i++)
 95         {
 96             dfs_order(son[x][i],k);
 97             bit.r[x]=max(bit.r[x],bit.r[son[x][i]]);
 98         }
 99     }
100 }tree;
101 
102 int x[M],ans[M],pre[N],now[N];
103 
104 inline int val(int x)
105 {
106     return bit.sum(bit.r[x])-bit.sum(bit.l[x]-1);
107 }
108 
109 void answer()
110 {
111     int m,i,j,y,v,p;
112     scanf("%d",&m);
113     memset(now,0,sizeof(now));
114     for (i=1;i<=m;i++)
115     {
116         scanf("%d%d",&x[i],&y);
117         x[i]=end[x[i]];
118         y=end[y];
119         pre[i]=now[y];
120         now[y]=i;
121     }
122     for (p=1,i=0;i<n;i++)
123     {
124         switch(s[i])
125         {
126             case 'P':
127             {
128                 for (j=now[p];j;j=pre[j])
129                     ans[j]=val(x[j]);
130                 break;
131             }
132             case 'B':
133             {
134                 bit.add(bit.l[p],-1);
135                 p=aca.fa[p];
136                 break;
137             }
138             default:
139             {
140                 v=s[i]-'a';
141                 p=aca.son[p][v];
142                 bit.add(bit.l[p],1);
143             }
144         }
145     }
146     for (i=1;i<=m;i++)
147         printf("%d\n",ans[i]);
148 }
149 
150 int main()
151 {
152     scanf("%s",s);
153     n=strlen(s);
154     aca.get_trie();
155     aca.get_fail();
156     tree.build();
157     int k=1;
158     tree.dfs_order(1,k);
159     answer();
160 }
View Code

 

posted @ 2016-04-20 22:03  KaNNe乄羽  阅读(137)  评论(0编辑  收藏  举报