阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机 上只有 28 个按键,分别印有 26 个小写英文字母和‘B‘、‘P‘两个字母。 经阿狸研究发现,这个打字机是这样工作的:
? 输入小写字母,打字机的一个凹槽中会加入这个字母(按 P 前凹槽中至 少有一个字母)。
? 按一下印有‘B‘的按键,打字机凹槽中最后一个字母会消失。
? 按一下印有‘P‘的按键,打字机会在纸上打印出凹槽中现有的所有字母并 换行,但凹槽中的字母不会消失(保证凹槽中至少有一个字母)。
例如,阿狸输入 aPaPBbP,纸上被打印的字符如下: a aa ab 我们把纸上打印出来的字符串从 1 开始顺序编号,一直到 n。打字机有一个 非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数 (x,y)(其中 1≤x,y≤n),打字机会显示第 x 个打印的字符串在第 y 个打印的字符串 中出现了多少次。 阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助 他么?
输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。 第二行包含一个整数 m,表示询问个数。 接下来 m 行描述所有由小键盘输入的询问。其中第 i 行包含两个整数 x, y, 表示第 i 个询问为(x, y)。
输出 m 行,其中第 i 行包含一个整数,表示第 i 个询问的答案。
样例输入
aPaPBbP
3
1 2
1 3
2 3
样例输出
2
1
0
看了好一会儿,。。。最终才发现是fail树上的区间询问。。原来想成了链剖。
fail树上一个点的父节点一直到根都是他的后缀,所以只要一个点x在fail树上的点y的子树内,x就包含y,所以查询a在b里出现了多少次
就是查询y的所有前缀在trie中代表的点在fail树上的对应点有多少在x的对应点的子树内。
先用一个栈快速建出包含所有P出来的串的一颗trie,然后直接getfail建出fail树。
然后dfs,依照dfs序把子树放到区间上。
然后把询问离线,注意fail树和trie树上的点以及询问的对应关系。。这个让我挂了好久。。最好让fail树和trie数上的同一个点用同一个数表示(数组下标嘛)
最后一遍dfs.遇到一个点就把他在线段树上加1.退出的时候就把这个点减1.如果这个点是一个‘b’点,就查询答案。
就是线段树单点修改,区间查询。
1 #include<iostream> 2 #include<cstdio> 3 #include<stack> 4 #include<queue> 5 #include<cstring> 6 using namespace std; 7 #define maxn 200000 8 struct seg_node{ 9 int l; 10 int r; 11 int val; 12 seg_node* left; 13 seg_node* right; 14 }zqq[maxn]; 15 seg_node* root1; 16 int ctot = 0; 17 inline void update(seg_node* x){ 18 x->val = x->left->val + x->right->val; 19 } 20 seg_node* build(int l,int r){ 21 seg_node* cur = &zqq[++ctot]; 22 cur->l = l; 23 cur->r = r; 24 cur->val = 0; 25 if(l == r){ 26 return cur; 27 } 28 int mid = (l+r) >>1; 29 cur->left= build(l,mid); 30 cur->right = build(mid+1,r); 31 return cur; 32 } 33 void modify(seg_node* cur,int pos,int va){ 34 if(cur->l == cur->r){ 35 cur->val = va; 36 return; 37 } 38 int mid = (cur->l+cur->r) >>1; 39 if(pos <= mid){ 40 modify(cur->left,pos,va); 41 } 42 else{ 43 modify(cur->right,pos,va); 44 } 45 update(cur); 46 } 47 int find(seg_node* cur,int l,int r){ 48 if(cur->l == l && cur->r == r){ 49 return cur->val; 50 } 51 int mid =(cur->l+cur->r) >>1; 52 if(r <= mid){ 53 return find(cur->left,l,r); 54 } 55 else if(l > mid){ 56 return find(cur->right,l,r); 57 } 58 else{ 59 return find(cur->left,l,mid) + find(cur->right,mid+1,r); 60 } 61 } 62 struct edge{ 63 int np; 64 int next; 65 }h[maxn*3]; 66 int tot = 1; 67 int head[maxn]; 68 void add(int x,int y){ 69 h[++tot] = (edge){y,head[x]}; 70 head[x] = tot; 71 } 72 struct node{ 73 int next[30]; 74 vector<pair<int,int> > lxl; 75 int fail; 76 int count; 77 }e[maxn]; 78 int cnt = 0; 79 stack<int> st; 80 int m; 81 int len; 82 char s[maxn]; 83 int root = 0; 84 queue<int> q; 85 void getfail(){ 86 q.push(root); 87 int now,cur,f; 88 e[root].fail = -1; 89 while(!q.empty()){ 90 now = q.front(); 91 q.pop(); 92 if(now == root){ 93 for(int i = 0;i<27;i++){ 94 if(e[now].next[i]){ 95 e[e[now].next[i]].fail = root; 96 add(root,e[now].next[i]); 97 q.push(e[now].next[i]); 98 } 99 } 100 continue; 101 } 102 for(int i = 0;i<27;i++){ 103 f = e[now].fail; 104 if(e[now].next[i]){ 105 cur = e[now].next[i]; 106 while(f != -1 && !e[f].next[i]){ 107 f = e[f].fail; 108 } 109 if(f == -1){ 110 e[cur].fail = root; 111 add(root,cur); 112 } 113 else{ 114 e[cur].fail = e[f].next[i]; 115 add(e[f].next[i],cur); 116 } 117 q.push(cur); 118 } 119 } 120 } 121 } 122 struct zqq{ 123 int x,y,ans; 124 }qs[maxn]; 125 int qq[maxn]; 126 int ccnt =0; 127 int li[maxn]; 128 int ri[maxn]; 129 int idx = 0; 130 void dfs(int x){ 131 li[x] = ++idx; 132 for(int ne = head[x];ne;ne = h[ne].next){ 133 dfs(h[ne].np); 134 } 135 ri[x] = idx; 136 } 137 void dfs1(int x){ 138 if(x == 8){ 139 int lxlgay = 111; 140 } 141 modify(root1,li[x],1); 142 int cur; 143 int nowy; 144 int nowid; 145 for(int i =0;i<e[x].lxl.size();i++){ 146 nowy = e[x].lxl[i].first; 147 nowid = e[x].lxl[i].second; 148 qs[nowid].ans = find(root1,li[qq[nowy]],ri[qq[nowy]]); 149 } 150 for(int i = 0;i<27;i++){ 151 if(e[x].next[i]){ 152 cur = e[x].next[i]; 153 dfs1(cur); 154 } 155 } 156 modify(root1,li[x],0); 157 } 158 int a1,a2; 159 int main(){ 160 scanf("%s",s); 161 len = strlen(s); 162 st.push(root); 163 int now; 164 for(int i = 0;i<len;i++){ 165 if(s[i] == ‘B‘){ 166 st.pop(); 167 } 168 else if(s[i] == ‘P‘){ 169 ccnt++; 170 qq[ccnt] = st.top(); 171 } 172 else{ 173 now = st.top(); 174 if(!e[now].next[s[i]-‘a‘]){ 175 cnt++; 176 e[now].next[s[i]-‘a‘] = cnt; 177 st.push(cnt); 178 } 179 else{ 180 st.push(e[now].next[s[i]-‘a‘]); 181 } 182 } 183 } 184 getfail(); 185 dfs(root); 186 scanf("%d",&m); 187 for(int i = 1;i<=m;i++){ 188 scanf("%d %d",&a1,&a2); 189 qs[i].x = a1; 190 qs[i].y = a2; 191 e[qq[a2]].lxl.push_back(pair<int,int>(a1,i)); 192 } 193 root1 = build(1,idx); 194 dfs1(root); 195 for(int i = 1;i<=m;i++){ 196 printf("%d\n",qs[i].ans); 197 } 198 return 0; 199 }