http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23083
Description
阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有28个按键,分别印有26个小写英文字母和‘B‘、‘P‘两个字母。
经阿狸研究发现,这个打字机是这样工作的:
l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后)。
l 按一下印有‘B‘的按键,打字机凹槽中最后一个字母会消失。
l 按一下印有‘P‘的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失。
例如,阿狸输入aPaPBbP,纸上被打印的字符如下:
a
aa
ab
我们把纸上打印出来的字符串从1开始顺序编号,一直到n。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数(x,y)(其中1≤x,y≤n),打字机会显示第x个打印的字符串在第y个打印的字符串中出现了多少次。
阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?
Sample Input
aPaPBbP31 21 32 3
Sample Output
210
题解:这道题做了好久。。哭泣。。。。。。。
主要是超时的问题。
fail树:按照AC自动机上fail的反向边建立的树。
如样例:
可以知道:failtree上,任意一点所代表的子串(即以trie上根到该点的串)是它在fail树上的子树任意一点的子串。
就是说,x是y的祖先,那么以y为结尾的串一直fail可以fail到x,就是x是y的子串。
那么现在可以得出一个简单粗暴的方法:
对于每个询问(x,y),求x在y上出现的次数,我们就可以在fail树上找到x串末尾的点A,然后询问y串在fail树上的每一个点是否是x的子树中的点,是就ans++。
但是明显,这个方法慢出天际了。。。。
优化:
(三颗星)离线。在fail树上用dfn给节点编号,则每一个点的子树在节点号上是连续的一段。在trie上走一遍,每到一个点x就在树状数组的dfn[x]位置+1,每离开一个点就在树状数组的dfn[x]位置-1。然后每当走到一个串的末尾,就询问每个对应要询问的x串,给fail树上它的子树求和,就是树状数组上getsum A~next[A]-1,这样就求出了y上多少个点为末尾可以fail到x,就是该询问(x,y)的答案。
后面就是我的错误点了:
(1)循环字符串的时候不要打for(int i=0;i<strlen(s);i++) ... 拿个变量存一下strlen(s)。。。超慢的。。
(2)做trietree的时候不用每次从头开始。。接着上一次的末尾就可以了。。快超多。。
(3)最后询问的时候不要把所有询问扫一遍。。用个first存y的边目录啊。。
血与泪啊。。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<vector> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 10 const int N=100010,S=26; 11 struct node{ 12 int k,fa,fail,son[30]; 13 }a[N]; 14 struct edge{ 15 int x,y,next,fa,ans; 16 }b[N],t[N]; 17 char s[N]; 18 int pre,m,tl,sl,num,cnt_s,len,cnt_dfn; 19 int last[N],c[N],sk[N],dfn[N],next[N],first[N],fir[N]; 20 queue<int> q; 21 22 void clear(int x) 23 { 24 a[x].fa=a[x].k=a[x].fail=0; 25 memset(a[x].son,0,sizeof(a[x].son)); 26 } 27 28 void buildAC() 29 { 30 while(!q.empty()) q.pop(); 31 for(int i=1;i<=S;i++) 32 if(a[0].son[i]) q.push(a[0].son[i]); 33 while(!q.empty()) 34 { 35 int x=q.front();q.pop(); 36 int fail=a[x].fail; 37 for(int i=1;i<=S;i++) 38 { 39 if(a[x].son[i]) 40 { 41 a[a[x].son[i]].fail=a[fail].son[i]; 42 q.push(a[x].son[i]); 43 } 44 else a[x].son[i]=a[fail].son[i]; 45 } 46 } 47 } 48 49 void ins(int x,int y,bool bk) 50 { 51 if(!bk) 52 { 53 b[++len].x=x;b[len].y=y; 54 b[len].next=first[x];first[x]=len; 55 } 56 else 57 { 58 t[++tl].x=x;t[tl].y=y;t[tl].ans=0; 59 t[tl].next=fir[x];fir[x]=tl; 60 } 61 } 62 63 void dfs(int x) 64 { 65 dfn[x]=++cnt_dfn; 66 for(int i=first[x];i;i=b[i].next) 67 { 68 int y=b[i].y; 69 dfs(y); 70 } 71 next[x]=cnt_dfn; 72 } 73 74 void build_fail_tree() 75 { 76 for(int i=1;i<=num;i++) ins(a[i].fail,i,0); 77 dfs(0); 78 } 79 80 int lowbit(int x){return x&(-x);} 81 void add(int x,int d){for(int i=x;i<=N-10;i+=lowbit(i)) c[i]+=d;} 82 int getsum(int x) 83 { 84 int ans=0; 85 for(int i=x;i>=1;i-=lowbit(i)) ans+=c[i]; 86 return ans; 87 } 88 89 int main() 90 { 91 freopen("a.in","r",stdin); 92 freopen("me.out","w",stdout); 93 num=0;cnt_s=0;cnt_dfn=0;len=0;pre=0;tl=0;clear(0); 94 memset(fir,0,sizeof(fir)); 95 memset(first,0,sizeof(first)); 96 memset(c,0,sizeof(c)); 97 scanf("%s",s); 98 //build trie tree 99 int strl=strlen(s),now=0; 100 for(int i=0;i<strl;i++) 101 { 102 if(s[i]==‘P‘) 103 { 104 a[now].k=1; 105 last[++cnt_s]=now; 106 } 107 else if(s[i]==‘B‘) now=a[now].fa; 108 else 109 { 110 int ind=s[i]-‘a‘+1; 111 if(!a[now].son[ind]) 112 { 113 num++;clear(num); 114 a[now].son[ind]=num; 115 a[num].fa=now; 116 } 117 now=a[now].son[ind]; 118 } 119 } 120 //build ac 121 buildAC(); 122 //build fail tree 123 build_fail_tree(); 124 scanf("%d",&m); 125 for(int i=1;i<=m;i++) 126 { 127 int x,y; 128 scanf("%d%d",&x,&y); 129 ins(y,x,1); 130 } 131 //find 132 now=0,cnt_s=0; 133 for(int i=0;i<strl;i++) 134 { 135 if(s[i]==‘B‘) 136 { 137 add(dfn[now],-1); 138 now=a[now].fa; 139 } 140 else if(s[i]==‘P‘) 141 { 142 cnt_s++; 143 for(int j=fir[cnt_s];j;j=t[j].next) 144 { 145 int st=dfn[last[t[j].y]],ed=next[last[t[j].y]]; 146 t[j].ans=getsum(ed)-getsum(st-1); 147 } 148 } 149 else 150 { 151 int ind=s[i]-‘a‘+1; 152 now=a[now].son[ind]; 153 add(dfn[now],1); 154 } 155 } 156 for(int i=1;i<=m;i++) 157 printf("%d\n",t[i].ans); 158 return 0; 159 }