[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 }