BZOJ2434: [Noi2011]阿狸的打字机(fail树+dfs序)

Description

 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和'B'、'P'两个字母。

经阿狸研究发现,这个打字机是这样工作的:

l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。

l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失。

l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。

例如,阿狸输入aPaPBbP,纸上被打印的字符如下:

a

aa

ab

我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。

阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

Input

 输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

第二行包含一个整数m,表示询问个数。

接下来m行描述所有由小键盘输入的询问。其中第i行包含两个整数x, y,表示第i个询问为(x, y)。

Output

 输出m行,其中第i行包含一个整数,表示第i个询问的答案。

Sample Input

aPaPBbP
3
1 2
1 3
2 3

Sample Output

2
1
0

解题思路:

长得像不像可持久化数据结构,这道题是可持久化Trie树

然而并没有强制在线a

曾经有个dalao说过:长得像可持久化+不强制在线=离线。

假如说没有问你a串在b串中出现多少次,BZOJ3172fail树裸上。

fail树中子节点个数为出现次数。

先按照打字顺序将trie树、trie图、fail树建好。

trie树要支持回溯(记录父节点)

将询问排序,按y串位置。

我们可以这样认为:

在询问版本中存在的点点权为1,不存在为0

这样统计子树大小时无需重构,更新点权即可。

再遍历原串。

遇到P

更新答案。

遇到其他:

改变一个点的点权。

当然不能暴力更新了。

询问子树权值和和更改单点点值当然要用dfs序了

代码:

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 const int N=1000000;
  6 struct trnt{
  7     int ch[26];
  8     int fl;
  9     int ind;
 10     int oud;
 11     int hd;
 12     int fa;
 13 }tr[N];
 14 struct ent{
 15     int twd;
 16     int lst;
 17 }e[N];
 18 struct qus{
 19     int asp;
 20     int plc;
 21     int no;
 22     int ans;
 23 }q[N];
 24 int lne[N];
 25 char ch[N];
 26 int fin[N];
 27 int len;
 28 int pct;
 29 int siz;
 30 int cnt;
 31 int n,m,dfn;
 32 std::queue<int>Q;
 33 void ade(int f,int t)
 34 {
 35     cnt++;
 36     e[cnt].twd=t;
 37     e[cnt].lst=tr[f].hd;
 38     tr[f].hd=cnt;
 39 }
 40 bool cmp(qus x,qus y)
 41 {
 42     return x.plc<y.plc;
 43 }
 44 bool cmq(qus x,qus y)
 45 {
 46     return x.no<y.no;
 47 }
 48 int lowbit(int x)
 49 {
 50     return x&(-x);
 51 }
 52 void add(int p,int v)
 53 {
 54     while(p<=len&&p)
 55     {
 56         lne[p]+=v;
 57         p+=lowbit(p);
 58     }
 59     return ;
 60 }
 61 int Val(int p)
 62 {
 63     int ans=0;
 64     while(p)
 65     {
 66         ans+=lne[p];
 67         p-=lowbit(p);
 68     }
 69     return ans;
 70 }
 71 void dfs(int x)
 72 {
 73     tr[x].ind=++dfn;
 74     for(int i=tr[x].hd;i;i=e[i].lst)
 75     {
 76         int to=e[i].twd;
 77         dfs(to);
 78     }
 79     tr[x].oud=dfn;
 80     return ;
 81 }
 82 void Build()
 83 {
 84     int root=0;
 85     len=strlen(ch+1);
 86     for(int i=1;i<=len;i++)
 87     {
 88         if(ch[i]=='P')
 89         {
 90             fin[++pct]=root;
 91         }else if(ch[i]=='B')
 92         {
 93             root=tr[root].fa;
 94         }else{
 95             int tmp=root;
 96             int c=ch[i]-'a';
 97             if(!tr[root].ch[c])
 98                 tr[root].ch[c]=++siz;
 99             root=tr[root].ch[c];
100             tr[root].fa=tmp;
101         }
102     }
103     root=0;
104     for(int i=0;i<26;i++)
105         if(tr[root].ch[i])
106             Q.push(tr[root].ch[i]);
107     while(!Q.empty())
108     {
109         root=Q.front();
110         Q.pop();
111         for(int i=0;i<26;i++)
112         {
113             if(tr[root].ch[i])
114             {
115                 tr[tr[root].ch[i]].fl=tr[tr[root].fl].ch[i];
116                 Q.push(tr[root].ch[i]);
117             }else
118                 tr[root].ch[i]=tr[tr[root].fl].ch[i];
119         }
120     }
121     for(int i=1;i<=siz;i++)
122         ade(tr[i].fl,i);
123     dfs(0);
124     return ;
125 }
126 void Get_ans()
127 {
128     std::sort(q+1,q+m+1,cmp);
129     int i=1;
130     int root=0;
131     int num=0;
132     for(int k=1;k<=len;k++)
133     {
134         if(ch[k]=='P')
135         {
136             num++;
137             while(q[i].plc<num&&i<=m)
138                 i++;
139             while(q[i].plc==num&&i<=m)
140             {
141                 int j=fin[q[i].asp];
142                 int h=Val(tr[j].oud);
143                 int o=Val(tr[j].ind-1);
144                 q[i].ans=h-o;
145                 i++;
146             }
147         }else if(ch[k]=='B')
148         {
149             add(tr[root].ind,-1);
150             root=tr[root].fa;
151         }else{
152             root=tr[root].ch[ch[k]-'a'];
153             add(tr[root].ind,1);
154         }
155     }
156     std::sort(q+1,q+m+1,cmq);
157     return ;
158 }
159 int main()
160 {
161     scanf("%s",ch+1);
162     scanf("%d",&m);
163     for(int i=1;i<=m;i++)
164     {
165         scanf("%d%d",&q[i].asp,&q[i].plc);
166         q[i].no=i;
167     }
168     Build();
169     Get_ans();
170     for(int i=1;i<=m;i++)
171         printf("%d
",q[i].ans);
172     return 0;
173 }
原文地址:https://www.cnblogs.com/blog-Dr-J/p/9674307.html