嗯---NOI水题集合之:阿狸的打字机

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机 上只有 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

看了好一会儿,。。。最终才发现是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 }

 

posted @ 2016-04-02 09:37  cx_oier  阅读(177)  评论(0编辑  收藏  举报