Bzoj2434 [Noi2011]阿狸的打字机
Submit: 2536 Solved: 1415
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
3
1 2
1 3
2 3
Sample Output
2
1
0
1
0
HINT
1<=N<=10^5
1<=M<=10^5
输入总长<=10^5
Source
先把字符串建成AC自动机,然后对fail指针建立DFS序,利用DFS序来差分答案。
默默打开了hzw学长的博客,默默开抄。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 #include<vector> 7 #define LL long long 8 using namespace std; 9 const int mxn=100010; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 struct edge{int v,nxt;}e[mxn<<1]; 17 int hd[mxn],mct=0; 18 void add_edge(int u,int v){ 19 e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return; 20 } 21 vector<int>ask[mxn];//询问 22 vector<int>id[mxn]; 23 int ans[mxn]; 24 // 25 int n,m; 26 char s[mxn]; 27 int ind[mxn],outd[mxn],sz=0; 28 int tr[mxn<<1]; 29 void add(int x,int v){while(x<=sz){tr[x]+=v;x+=x&-x;}} 30 int smm(int x){ 31 int res=0; 32 while(x){res+=tr[x];x-=x&-x;} 33 return res; 34 } 35 int pos[mxn],sct=0; 36 struct Aca{ 37 int t[mxn][26],fail[mxn]; 38 int fa[mxn]; 39 int rt,cnt; 40 void clear(){cnt=1;rt=1;for(int i=0;i<26;i++)t[0][i]=1;} 41 void insert(char s[]){ 42 int now=rt; 43 int len=strlen(s); 44 for(int i=0;i<len;i++){ 45 if(s[i]=='P'){pos[++sct]=now;continue;} 46 else if(s[i]=='B'){now=fa[now];continue;} 47 if(!t[now][s[i]-'a']){ 48 t[now][s[i]-'a']=++cnt; 49 fa[t[now][s[i]-'a']]=now; 50 } 51 now=t[now][s[i]-'a']; 52 } 53 } 54 void Build(){ 55 queue<int>q; 56 q.push(rt); 57 fail[1]=0; 58 while(!q.empty()){ 59 int now=q.front();q.pop(); 60 for(int i=0;i<26;i++){ 61 if(t[now][i]){ 62 int k=fail[now]; 63 while(!t[k][i])k=fail[k]; 64 fail[t[now][i]]=t[k][i]; 65 q.push(t[now][i]); 66 } 67 } 68 } 69 } 70 }aca; 71 void DFS(int u){ 72 ind[u]=++sz; 73 for(int i=hd[u];i;i=e[i].nxt){ 74 DFS(e[i].v); 75 } 76 outd[u]=++sz; 77 return; 78 } 79 int main() 80 { 81 int i,j,u,v; 82 scanf("%s",s); 83 n=strlen(s); 84 aca.clear(); 85 aca.insert(s); 86 aca.Build(); 87 for(int i=aca.rt;i<=aca.cnt;i++){ 88 add_edge(aca.fail[i],i); 89 } 90 DFS(0); 91 m=read(); 92 for(i=1;i<=m;i++){ 93 u=read();v=read(); 94 ask[v].push_back(u); 95 id[v].push_back(i); 96 } 97 int now=aca.rt;int t=0; 98 // 99 add(ind[1],1);//add(outd[1],-1); 100 for(i=0;i<n;i++){ 101 // printf("now: %c \n",s[i]); 102 if(s[i]=='P'){ 103 t++; 104 u=t; 105 for(j=0;j<ask[u].size();j++){ 106 v=pos[ask[u][j]]; 107 // printf("%d to %d\n",ind[v],outd[v]); 108 // printf("%d %d\n",smm(outd[v]),smm(ind[v]-1)); 109 ans[id[u][j]]=smm(outd[v])-smm(ind[v]-1); 110 } 111 continue; 112 } 113 else if(s[i]=='B'){ 114 add(ind[now],-1);//add(outd[now],1); 115 now=aca.fa[now];continue; 116 } 117 now=aca.t[now][s[i]-'a']; 118 add(ind[now],1);//add(outd[now],-1); 119 } 120 // 121 for(i=1;i<=m;i++)printf("%d\n",ans[i]); 122 return 0; 123 }
本文为博主原创文章,转载请注明出处。