BZOJ 2434 [Noi2011] 阿狸的打字机 Fail树
2017-01-17 19:55
603 查看
2017.3.17补…
题目大意:造一台打字机(滑稽),要求支持:1.在末尾添加一个字符 2.删除结尾字符 3.打印当前字符串 4.回答打印出的第x个字符串在第y个字符串中出现了几次。
询问一个字符串在另一个字符串中的出现次数可以想到利用AC自动机中构造出的Fail树的性质(类似BZOJ3172)。要如何回答询问呢?
查询x在y中出现了几次,就是查询Fail树上x的子树中有多少个结点属于y.
这样的话,维护一个dfs序的树状数组(因为想求子树和,且子树在dfs序中是连续的),而对于一个单词,将他的所有节点插入到树状数组后就可以处理所有与其有关的询问。把所有询问建成一个邻接表,遇到P就处理所有有关这个字符串的询问,最后一起输出即可。
题目大意:造一台打字机(滑稽),要求支持:1.在末尾添加一个字符 2.删除结尾字符 3.打印当前字符串 4.回答打印出的第x个字符串在第y个字符串中出现了几次。
询问一个字符串在另一个字符串中的出现次数可以想到利用AC自动机中构造出的Fail树的性质(类似BZOJ3172)。要如何回答询问呢?
查询x在y中出现了几次,就是查询Fail树上x的子树中有多少个结点属于y.
这样的话,维护一个dfs序的树状数组(因为想求子树和,且子树在dfs序中是连续的),而对于一个单词,将他的所有节点插入到树状数组后就可以处理所有与其有关的询问。把所有询问建成一个邻接表,遇到P就处理所有有关这个字符串的询问,最后一起输出即可。
#include <cstdio> #include <cstring> #include <queue> #include <vector> #define pb push_back #define N 100005 using namespace std; struct Edge { int u,v,nxt,ans; }query ; int fir ,st ,ed ; struct Node { Node *ch[26],*fail,*pa; int val,pos; vector<Node*> to; Node():val(0),fail(NULL),pa(NULL),pos(0) { to.clear(); memset(ch,0,sizeof ch); } }*root=new Node(); int len,tot; char s ; void Insert() { Node* o=root; for(int i=0;i<len;i++) { if(s[i]=='P') o->val=++tot; else if(s[i]=='B') o=o->pa; else { int z=s[i]-'a'; if(!o->ch[z]) o->ch[z]=new Node(), o->ch[z]->pa=o; o=o->ch[z]; } } return ; } void getFail() { queue<Node*> q; Node* o=root; for(int i=0;i<26;i++) if(o->ch[i]) { q.push(o->ch[i]); o->ch[i]->fail=o; o->to.pb(o->ch[i]); } else o->ch[i]=o; while(!q.empty()) { o=q.front(); q.pop(); for(int i=0;i<26;i++) if(o->ch[i]) { q.push(o->ch[i]); o->ch[i]->fail=o->fail->ch[i]; o->fail->ch[i]->to.pb(o->ch[i]); } else o->ch[i]=o->fail->ch[i]; } return ; } int T; namespace BIT { int c ; inline int lowbit(int x) {return x&-x;} void add(int x,int y) { for(int i=x;i<=T;i+=lowbit(i)) c[i]+=y; return ; } int sum(int x) { int tmp=0; for(int i=x;i;i-=lowbit(i)) tmp+=c[i]; return tmp; } } ///build FailTree void dfs(Node* o) { o->pos=++T; if(o->val) st[o->val]=T; for(int i=0;i<o->to.size();i++) dfs(o->to[i]); if(o->val) ed[o->val]=T; return ; } void solve() { using namespace BIT; Node* o=root; for(int i=0;i<len;i++) { if(s[i]=='B') add(o->pos,-1), o=o->pa; else if(s[i]=='P') for(int j=fir[o->val];j;j=query[j].nxt) query[j].ans=sum(ed[query[j].v])-sum(st[query[j].v]-1); else { int z=s[i]-'a'; o=o->ch[z]; add(o->pos,1); } } return ; } int main() { scanf("%s",s); len=strlen(s); Insert(); getFail(); dfs(root); int n; scanf("%d",&n); for(int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); query[i].u=y; query[i].v=x; query[i].nxt=fir[y]; fir[y]=i; } solve(); for(int i=1;i<=n;i++) printf("%d\n",query[i].ans); return 0; }
相关文章推荐
- LightOJ 1236 Pairs Forming LCM(唯一分解定理)
- 密码正确,SSH无法登陆 Password authentication failed /Permission denied, please try again.
- 当 AlphaGo 升级版本 Master 横扫围棋大师,我们来聊聊如何学习AI
- wait和notify区别
- BIO与NIO、AIO的区别(这个容易理解)
- HDU1022--Train Problem I(栈的应用)
- Rails多路径调用相同方法原路返回的方法
- Rails多路径调用相同方法原路返回的方法
- Rails多路径调用相同方法原路返回的方法
- 【AI每日播报】Jeff Dean回顾 Google Brain 2016:机器学习取得重大进展
- socketpair
- Fintech前沿技术周报【2017-1-17】
- BZOJ 3172 [Tjoi2013] 单词 Fail树
- Rails报找不到sanitize和raw方法的解决
- Rails报找不到sanitize和raw方法的解决
- Rails报找不到sanitize和raw方法的解决
- JVM:线程状态park, wait, sleep, interrupt, yeild 对比
- 解决办法:CREATE_LISTENER_FAILED_4异常
- vim 命令大全(写的非常全和好)http://blog.csdn.net/woshixiaosimao/article/details/54312738
- Google 超分辨率技术 RAISR:模糊图片瞬间变清晰,运算速度快十倍