【BZOJ2434-[Noi2011]】阿狸的打字机(AC自动机(fail树)+离线+树状数组)
2016-06-16 16:39
447 查看
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
aPaPBbP3
1 2
1 3
2 3
Sample Output
21
0
HINT
1<=N<=10^51<=M<=10^5
输入总长<=10^5
【分析】
这道题是用AC自动机里的fail指针连成的树做的。
用到fail树。
首先有一个朴素算法就是找到第y个单词在trie树上的路径然后沿着每一个点的fail指针走,如果找到x就加1(想想fail指针建立的过程)。
由此可以运用逆向思维,以x为根的子树沿着fail指针倒着走能找到多少个y路径上的点就说明x在y上出现过几次。每次都dfs找一遍,用树状数组维护,这样可以得到70分。
同时这是一个离线算法,一遍dfs,遇到一个结束标记,就做一下这个串的询问,插一个点在树状数组+1,离开这个点时-1。
对于树上每个点只插入一次,时间复杂度就得到了保证。
有一个很详细的题解:http://blog.csdn.net/huzecong/article/details/7769988
代码如下:(丑)
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define Maxn 100100 #define Maxl 100010 char s[Maxl]; int p[Maxn]; struct hp { int x,y,next,id,ans; }qy[Maxn];int al; struct node { int son[30],cnt,fail; int num,rt,fa,st; }t[Maxn];int tot; int first[Maxn],c[Maxn]; bool cmp(hp x,hp y) {return p[x.y]<p[y.y];} bool cmp2(hp x,hp y) {return x.id<y.id;} void ins(int x,int y) { qy[++al].x=x;qy[al].y=y; qy[al].next=first[x];first[x]=al; } void upd(int x,int f) { t[x].cnt=0;t[x].fa=f;t[x].st=0; memset(t[x].son,0,sizeof(t[x].son)); } void read_trie() { scanf("%s",s+1); int len=strlen(s+1); memset(p,0,sizeof(p)); int now=0;int ql=0;tot=0; for(int j=1;j<=len;j++) { if(s[j]>='a'&&s[j]<='z') { int ind=s[j]-'a'+1; if(!t[now].son[ind]) t[now].son[ind]=++tot,upd(tot,now); now=t[now].son[ind]; if(j==len) t[now].cnt++; } else if(s[j]=='B') now=t[now].fa; else p[++ql]=now; } } queue<int > q; void build_AC() { int i,j,x,y; while(!q.empty()) q.pop(); q.push(0); while(!q.empty()) { x=q.front(); y=t[x].fail; for(j=1;j<=26;j++) { if(t[x].son[j]) { q.push(t[x].son[j]); t[t[x].son[j]].fail=x?t[y].son[j]:x; ins(t[t[x].son[j]].fail,t[x].son[j]); } else t[x].son[j]=t[y].son[j]; } q.pop(); } } void dfs(int x) { t[x].num=++al;t[x].rt=t[x].num; for(int i=first[x];i;i=qy[i].next) dfs(qy[i].y),t[x].rt=t[qy[i].y].rt; } void add(int x,int y) { for(int i=x;i<=tot+1;i+=i&(-i)) c[i]+=y; } int getsum(int x) { int ans=0; for(int i=x;i>=1;i-=i&(-i)) ans+=c[i]; return ans; } void dfs2(int x) { add(t[x].num,1); if(t[x].st!=0) { for(int i=t[x].st;;i++) { if(p[qy[i].y]!=x) break; qy[i].ans=getsum(t[p[qy[i].x]].rt)-getsum(t[p[qy[i].x]].num-1); } } for(int i=1;i<=26;i++) if(t[x].son[i]&&t[t[x].son[i]].fa==x) { dfs2(t[x].son[i]); } add(t[x].num,-1); } void init() { memset(first,0,sizeof(first)); al=0; read_trie(); build_AC();al=0; dfs(0); int m; scanf("%d",&m); for(int i=1;i<=m;i++) {scanf("%d%d",&qy[i].x,&qy[i].y);qy[i].id=i;} sort(qy+1,qy+1+m,cmp); qy[0].y=0; for(int i=1;i<=m;i++) if(p[qy[i].y]!=p[qy[i-1].y]) t[p[qy[i].y]].st=i; else t[p[qy[i].y]].st=t[p[qy[i-1].y]].st; memset(c,0,sizeof(c)); dfs2(0); sort(qy+1,qy+1+m,cmp2); for(int i=1;i<=m;i++) printf("%d\n",qy[i].ans); } int main() { init(); return 0; }
[BZOJ2434]
2016-06-16 16:55:20
相关文章推荐
- DDD(Domain Driver Designer) 领域驱动设计简介
- POJ 1681 Painter's Problem(高斯消元)
- 关于部分手机通话录音报start failed的问题
- 【leetcode】172. Factorial Trailing Zeroes
- WSASocket failed 10013 处理
- 打开金蝶AIS文件方法
- Redis redis.clients.jedis.exceptions.JedisDataException: ERR Operation against a key holding the wr
- 转载http://jingyan.baidu.com/article/bad08e1e87138209c8512118.html
- AIDL进程间通讯的一些注意问题
- CDISC SDTM DS domain学习笔记
- oracle查看允许的最大连接数和当前连接数等信息(转自:http://blog.csdn.net/haiross/article/details/41944493)
- 钥匙串KeyChain的使用
- “机器学习”相关资料分享
- tail和head命令
- INS-35172 Target database memory(945MB) excessds the systems available shared memory({0}MB)
- 工作于内存和文件之间的页缓存, Page Cache, the Affair Between Memory and Files
- Paint House
- Openstack组件部署 — keystone(domain, projects, users, and roles)
- 2D Closest Pair Problem
- 朴素贝叶斯简易解释