BZOJ2434: [Noi2011]阿狸的打字机
2434: [Noi2011]阿狸的打字机
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1166 Solved: 656
[Submit][Status]
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[i]作为i的父亲构建fail树,那么如果要查询s[x]在s[y]中出现了多少次,实际上就是询问
s[x]的结尾节点的子树中有多少是s[y]的节点。
考虑离线的做法,我们对每一个结尾节点保存一个链表表示要查询哪个串在该串中出现的次数。
我们发现有子树查询,然后按fail树进行dfs序,标记l[x],r[x]分别为左端点和右端点。
然后继续,我们在trie上dfs
View Code
View Code
终于填上了一个大坑。。。
首先我们建出AC自动机,然后以fail[i]作为i的父亲构建fail树,那么如果要查询s[x]在s[y]中出现了多少次,实际上就是询问
s[x]的结尾节点的子树中有多少是s[y]的节点。
考虑离线的做法,我们对每一个结尾节点保存一个链表表示要查询哪个串在该串中出现的次数。
我们发现有子树查询,然后按fail树进行dfs序,标记l[x],r[x]分别为左端点和右端点。
然后继续,我们在trie上dfs
inline void dfs2(int x) { add(l[x],1); for(int i=head[1][a[x]];i;i=e[1][i].next)ans[i]=sum(r[b[e[1][i].go]])-sum(l[b[e[1][i].go]]-1); for0(i,25)if(t[x][i]>x)dfs2(t[x][i]); add(r[x],-1); }
可以看出,当我们到达x节点时,只有根到x的节点的括号序列是没有闭合的,呈现(,而已经访问结束的或者未访问的呈现()或 空,这样它们对答案的贡献都是0
所以我们执行直接求和sum(l[x]-r[x])就可以求出s[y]的节点中有多少个是s[x]的子树。
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 250000+5 26 27 #define maxm 20000000+5 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 45 using namespace std; 46 47 inline int read() 48 49 { 50 51 int x=0,f=1;char ch=getchar(); 52 53 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 54 55 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 56 57 return x*f; 58 59 } 60 int n,m,mm,cnt,tot[2],head[2][maxn],t[maxn][26],go[maxn],l[maxn],r[maxn]; 61 int ans[maxn],a[maxn],b[maxn],p[maxn],pre[maxn],s[maxn]; 62 struct edge{int go,next;}e[2][maxn]; 63 queue<int>q; 64 char st[maxn]; 65 inline void insert(int k,int x,int y) 66 { 67 e[k][++tot[k]]=(edge){y,head[k][x]};head[k][x]=tot[k]; 68 } 69 void bfs() 70 { 71 q.push(1); 72 while(!q.empty()) 73 { 74 int x=q.front(),y,j;q.pop(); 75 for0(i,25)if(t[x][i]) 76 { 77 j=go[x]; 78 while(j&&!t[j][i])j=go[j]; 79 go[y=t[x][i]]=j?t[j][i]:1; 80 insert(0,go[y],y); 81 q.push(y); 82 } 83 } 84 } 85 inline void add(int x,int y){for(;x<=2*n;x+=x&(-x))s[x]+=y;} 86 inline int sum(int x){int t=0;for(;x;x-=x&(-x))t+=s[x];return t;} 87 inline void dfs(int x) 88 { 89 l[x]=++mm; 90 for(int i=head[0][x];i;i=e[0][i].next)dfs(e[0][i].go); 91 r[x]=++mm; 92 } 93 inline void dfs2(int x) 94 { 95 add(l[x],1); 96 for(int i=head[1][a[x]];i;i=e[1][i].next)ans[i]=sum(r[b[e[1][i].go]])-sum(l[b[e[1][i].go]]-1); 97 for0(i,25)if(t[x][i]>x)dfs2(t[x][i]); 98 add(r[x],-1); 99 } 100 void putint(int t ){ 101 if(! t )putchar('0') 102 ;else{ 103 int a[20]; 104 a[0]=0; 105 for(;t;t/=10)a[++a[0]]=t%10; 106 for3(i,a[0],1)putchar('0'+a[i]); 107 } 108 putchar('\n'); 109 } 110 111 int main() 112 113 { 114 115 freopen("input.txt","r",stdin); 116 117 freopen("output.txt","w",stdout); 118 119 n=0; 120 while(1) 121 { 122 char ch=getchar(); 123 if(ch=='B'||ch=='P'||(ch<='z'&&ch>='a'))st[++n]=ch; 124 if(ch=='\r'||ch=='\n')break; 125 } 126 m=read(); 127 for1(i,m) 128 { 129 int x=read(),y=read(); 130 insert(1,y,x); 131 } 132 int now=cnt=1,id=0; 133 for1(i,n) 134 if(st[i]=='P')a[now]=++id,b[id]=now; 135 else if(st[i]=='B'){p[i]=now;now=pre[now];} 136 else 137 { 138 int x=st[i]-'a'; 139 if(!t[now][x])t[now][x]=++cnt,pre[cnt]=now; 140 now=t[now][x];p[i]=now; 141 } 142 bfs(); 143 dfs(1); 144 dfs2(1); 145 for1(i,m)putint(ans[i]); 146 147 return 0; 148 149 }
还有一种查询方法如下,蒟蒻表示理解不能。。。
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 250000+5 26 27 #define maxm 20000000+5 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 45 using namespace std; 46 47 inline int read() 48 49 { 50 51 int x=0,f=1;char ch=getchar(); 52 53 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 54 55 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 56 57 return x*f; 58 59 } 60 int n,m,mm,cnt,tot[2],head[2][maxn],t[maxn][26],go[maxn],l[maxn],r[maxn]; 61 int ans[maxn],pos[maxn],p[maxn],pre[maxn],s[maxn]; 62 struct edge{int go,next;}e[2][maxn]; 63 queue<int>q; 64 char st[maxn]; 65 inline void insert(int k,int x,int y) 66 { 67 e[k][++tot[k]]=(edge){y,head[k][x]};head[k][x]=tot[k]; 68 } 69 void bfs() 70 { 71 q.push(1); 72 while(!q.empty()) 73 { 74 int x=q.front(),y,j;q.pop(); 75 for0(i,25) 76 { 77 j=go[x]; 78 while(j&&!t[j][i])j=go[j]; 79 if(t[x][i]) 80 { 81 go[y=t[x][i]]=j?t[j][i]:1; 82 insert(0,go[y],y); 83 q.push(y); 84 }else t[x][i]=j?t[j][i]:1; 85 } 86 } 87 } 88 inline void add(int x,int y){for(;x<=2*n;x+=x&(-x))s[x]+=y;} 89 inline int sum(int x){int t=0;for(;x;x-=x&(-x))t+=s[x];return t;} 90 inline void dfs(int x) 91 { 92 l[x]=++mm; 93 for(int i=head[0][x];i;i=e[0][i].next)dfs(e[0][i].go); 94 r[x]=++mm; 95 } 96 void putint(int t ){ 97 if(! t )putchar('0') 98 ;else{ 99 int a[20]; 100 a[0]=0; 101 for(;t;t/=10)a[++a[0]]=t%10; 102 for3(i,a[0],1)putchar('0'+a[i]); 103 } 104 putchar('\n'); 105 } 106 107 int main() 108 109 { 110 111 freopen("input.txt","r",stdin); 112 113 freopen("output.txt","w",stdout); 114 115 n=0; 116 while(1) 117 { 118 char ch=getchar(); 119 if(ch=='B'||ch=='P'||(ch<='z'&&ch>='a'))st[++n]=ch; 120 if(ch=='\r'||ch=='\n')break; 121 } 122 m=read(); 123 for1(i,m) 124 { 125 int x=read(),y=read(); 126 insert(1,y,x); 127 } 128 int now=cnt=1,id=0; 129 for1(i,n) 130 if(st[i]=='P')pos[++id]=now; 131 else if(st[i]=='B'){p[i]=now;now=pre[now];} 132 else 133 { 134 int x=st[i]-'a'; 135 if(!t[now][x])t[now][x]=++cnt,pre[cnt]=now; 136 now=t[now][x];p[i]=now; 137 } 138 bfs(); 139 dfs(1); 140 id=0; 141 for1(i,n) 142 if(st[i]=='P'){for(int j=head[1][++id];j;j=e[1][j].next)ans[j]=sum(r[pos[e[1][j].go]])-sum(l[pos[e[1][j].go]]-1);} 143 else if(st[i]=='B')add(r[p[i]],-1);else add(l[p[i]],1); 144 for1(i,m)putint(ans[i]); 145 return 0; 146 147 }