[BZOJ2434]阿狸的打字机
2434: [Noi2011]阿狸的打字机
Time Limit: 10 Sec Memory Limit: 256 MBDescription
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有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
3
1 2
1 3
2 3
Sample Output
2
1
0
1
0
HINT
1<=N,M<=10^5
输入总长<=10^5
题解:
之前听liu_runda学长讲过一遍……
建树时B,P两个操作很容易处理
我们考虑,对于两个字符串s[x],s[y],
x在y中出现的次数,等于y到root的trie路径中,在x的fail树子树中的节点个数
(其实很好理解,如果某个节点在x的fail树里,那么以这个节点结束的子串里至少有一个x串)
但是,如果我们每次都在线一个一个查询,会T(比如用倍增,复杂度O(M*len*log(len)))
那么我们可以离线,记录dfs序并且用树状数组统计节点数,复杂度
于是这道题就被我们A掉了,代码见下:
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<vector> 5 using namespace std; 6 const int L=100000; 7 int m,num,cnt,cnt_type,hd=1,tl;char text[L+100]; 8 int e,adj[L+100],bit[L+100],ans[L+100]; 9 inline int lowbit(int a){return a&-a;} 10 inline void add(int pos,int val) 11 { 12 while(pos<=cnt) 13 bit[pos]+=val,pos+=lowbit(pos); 14 } 15 inline int sum(int pos) 16 { 17 int ret=0; 18 while(pos) 19 ret+=bit[pos],pos-=lowbit(pos); 20 return ret; 21 } 22 struct node 23 { 24 node *f,*fa,*ch[26]; 25 int id,dfn_l,dfn_r,mark; 26 node(int v,node *o) 27 { 28 memset(ch,0,sizeof(ch)); 29 id=v,mark=0;fa=o,f=NULL; 30 } 31 }*root=new node(0,NULL),*q[L+100],*print[L+100]; 32 struct edge{node *qi,*zhong;int next;}s[L+100]; 33 inline void get_fail() 34 { 35 q[++tl]=root; 36 while(hd<=tl) 37 { 38 node *rt=q[hd++]; 39 for(int i=0;i<26;i++) 40 { 41 if(rt->ch[i]) 42 { 43 q[++tl]=rt->ch[i]; 44 node *u=rt->f; 45 while(u&&!u->ch[i])u=u->f; 46 rt->ch[i]->f=(u)?u->ch[i]:root; 47 } 48 } 49 } 50 } 51 inline void add(node *qi,node *zhong) 52 { 53 s[++e].qi=qi;s[e].zhong=zhong; 54 s[e].next=adj[qi->id],adj[qi->id]=e; 55 } 56 inline void build_fail(node *rt) 57 { 58 for(int i=0;i<26;i++) 59 if(rt->ch[i]!=NULL) 60 add(rt->ch[i]->f,rt->ch[i]),build_fail(rt->ch[i]); 61 } 62 void dfs(node *rt) 63 { 64 rt->dfn_l=++cnt; 65 for(int i=adj[rt->id];i;i=s[i].next) 66 if(s[i].zhong!=NULL) 67 dfs(s[i].zhong); 68 rt->dfn_r=cnt; 69 } 70 struct Quest{int id;node *pos;}; 71 vector<Quest>quest[L+100]; 72 void work(node *rt) 73 { 74 add(rt->dfn_l,1); 75 for(int i=0;i<quest[rt->id].size();i++) 76 { 77 Quest t=quest[rt->id][i]; 78 ans[t.id]=sum(t.pos->dfn_r)-sum(t.pos->dfn_l-1); 79 } 80 for(int i=0;i<26;i++) 81 if(rt->ch[i]!=NULL) 82 work(rt->ch[i]); 83 add(rt->dfn_l,-1); 84 } 85 int main() 86 { 87 scanf("%s",text);int sea=strlen(text); 88 node *now=root; 89 for(int i=0;i<sea;i++) 90 { 91 if(text[i]=='P') 92 { 93 now->mark=++cnt_type; 94 print[cnt_type]=now; 95 } 96 else if(text[i]=='B') 97 now=now->fa; 98 else 99 { 100 if(!now->ch[text[i]-'a']) 101 now->ch[text[i]-'a']=new node(++num,now); 102 now=now->ch[text[i]-'a']; 103 } 104 } 105 get_fail();build_fail(root);dfs(root); 106 scanf("%d",&m);int x,y; 107 for(int i=1;i<=m;i++) 108 { 109 scanf("%d%d",&x,&y); 110 quest[print[y]->id].push_back((Quest){i,print[x]}); 111 } 112 work(root); 113 for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 114 }
Progress is not created by contented people.