bzoj2434: [Noi2011]阿狸的打字机
2016-04-10 21:07
483 查看
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434
题意:中文题。
分析:给定一个这样的字符串很容易就想建一颗trie树。然后在trie树上进行匹配,这不就是AC自动机么!我们可以直接考虑这样的一种暴力,当查询x,y时我们只要将从root到y路径上所有的点沿着fail跑一遍,只要经过一次x就ans+1。但是这样会超时,我们在观察这个结构的特征,然后会发现fail[i]是唯一的那么反向的话就是一颗树咯!那样就是在x的子树中找在路径root-y上的点的个数咯。子树中的统计问题我们很容易就能想到用dfs序来处理成区间问题,那root-y上的点呢?我们可以按照建trie树的过程去处理,当走到y时我们就将所有{x}-y的问题全部处理掉,我们只要在遇到小写字母时就将它的in[i]位置插入1,遇到B是就将当前位置减去1,那么当我们遇到y是就只剩下一条链上的in[i]的位置上有1了,那么答案就是区间[in[x],out[x]]中的1的个数咯,用过树状数组维护下就好了。
代码:
#include<map> #include<set> #include<cmath> #include<queue> #include<bitset> #include<math.h> #include<cstdio> #include<vector> #include<string> #include<cstring> #include<iostream> #include<algorithm> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; const int N=100100; const int MAX=100000000; const int mod=100000000; const int MOD1=1000000007; const int MOD2=1000000009; const double EPS=0.00000001; typedef long long ll; const ll MOD=998244353; const ll INF=10000000010; typedef double db; typedef unsigned long long ull; int tot,u ,v ,w ,pre ; void add(int x,int y,int z) { v[tot]=y;w[tot]=z;pre[tot]=u[x];u[x]=tot++; } char s ; struct trie { int g,m,sz,X ,fa ,val ,fail ,tr [26]; int ttot,tu ,tv ,tpre ; int k,in ,out ; void trie_clear() { k=g=m=sz=ttot=0; memset(tu,-1,sizeof(tu)); } void trie_insert(char *ch) { while (*ch!='\0') { if (*ch=='B') { m=fa[m];ch++;continue ; } if (*ch=='P') { val[m]=++g;X[g]=m;ch++;continue ; } if (tr[m][*ch-'a']) { m=tr[m][*ch-'a'];ch++; } else { fa[sz+1]=m;tr[m][*ch-'a']=++sz;m=sz;ch++; } } } void trie_build() { queue<int>Q; for (int i=0;i<26;i++) if (tr[0][i]) Q.push(tr[0][i]); while (!Q.empty()) { int now=Q.front();Q.pop(); for (int i=0;i<26;i++) if (tr[now][i]) { fail[tr[now][i]]=tr[fail[now]][i]; Q.push(tr[now][i]); } else tr[now][i]=tr[fail[now]][i]; } } void add(int x,int y) { tv[ttot]=y;tpre[ttot]=tu[x];tu[x]=ttot++; } void add_b() { for (int i=0;i<=sz;i++) if (fail[i]!=i) add(fail[i],i); } void dfs(int x) { k++;in[x]=k; for (int i=tu[x];i!=-1;i=tpre[i]) dfs(tv[i]); out[x]=k; } }ac; int len,f ,ans ; void updata(int x,int y) { for (;x<=len+1;x+=x&(-x)) f[x]+=y; } int getsum(int x) { int ret=0; for (;x;x-=x&(-x)) ret+=f[x]; return ret; } int main() { int i,j,n,x,y; scanf("%s", s); ac.trie_clear(); ac.trie_insert(s); ac.trie_build(); ac.add_b();ac.dfs(0); scanf("%d", &n); tot=0;memset(u,-1,sizeof(u)); for (i=1;i<=n;i++) { scanf("%d%d", &x, &y);add(y,x,i); } len=strlen(s);x=0; memset(f,0,sizeof(f)); for (i=0;i<len;i++) { if (s[i]=='B') { updata(ac.in[x],-1);x=ac.fa[x];continue ; } if (s[i]=='P') { for (j=u[ac.val[x]];j!=-1;j=pre[j]) { ans[w[j]]=getsum(ac.out[ac.X[v[j]]])-getsum(ac.in[ac.X[v[j]]]-1); } continue ; } x=ac.tr[x][s[i]-'a'];updata(ac.in[x],1); } for (i=1;i<=n;i++) printf("%d\n", ans[i]); return 0; }
相关文章推荐
- 第七周:可执行程序的装载
- 找出第n个ugly number
- UML之行为图(活动图、状态图、交互图)
- ES6-新数据结构Map
- 1090. Highest Price in Supply Chain (25)
- 二叉树的中序遍历
- Best Time to Buy and Sell Stock 带测试版本
- Centos 7 远程桌面客户端
- 016.php循环do-while、for语句
- python爬虫学习之抓取一个页面
- raspbian重置密码
- Android开发学习之路-Android Studio真神器!
- 爬虫是什么?
- 2016华为机试之矩形重合面积
- 进阶版《结对编程》
- Java 设计模式之Singleton~~
- jsp做的留言系统(防止非法登录、增删改查留言)
- [置顶] JavaSE学习笔记_18:Java-IO流
- ng-attr-(suffix)
- 用Python写一个文本转HTML的脚本