AC自动机
光看课件觉得脑洞挺大的,,,然而模板在手天下我有
- 先来道模板题
hdu2222
1 #include<stdio.h> 2 #include<string.h> 3 4 #define maxn 1000005 5 char t[maxn],s[maxn]; 6 int tot,trie[maxn][26],mark[maxn],fail[maxn],Q[maxn]; 7 8 void add(char *t){ 9 int p=0,i; 10 for(int i=1;t[i];i++){ 11 if(!trie[p][t[i]-'a'])trie[p][t[i]-'a']=++tot; 12 p=trie[p][t[i]-'a']; 13 } 14 mark[p]++; 15 } 16 void build(){ 17 int head=0,tail=0; 18 Q[++tail]=0; 19 while(head<tail){ 20 int x=Q[++head]; 21 for(int i=0;i<26;i++){ 22 if(trie[x][i]){ 23 Q[++tail]=trie[x][i]; 24 fail[trie[x][i]]=x?trie[fail[x]][i]:0; 25 } 26 else trie[x][i]=trie[fail[x]][i]; 27 } 28 } 29 } 30 int main(){ 31 int T; 32 scanf("%d",&T); 33 while(T--){ 34 memset(trie,0,sizeof(trie)); 35 memset(mark,0,sizeof(mark)); 36 tot=0; 37 int n; 38 scanf("%d",&n); 39 for(int i=1;i<=n;i++){ 40 scanf("%s",t+1); 41 add(t); 42 } 43 build(); 44 scanf("%s",s+1); 45 int p=0,ans=0; 46 for(int i=1;s[i];i++){ 47 p=trie[p][s[i]-'a']; 48 int pp=p; 49 while(pp&&mark[pp]){ 50 ans+=mark[pp]; 51 mark[pp]=0; 52 pp=fail[pp]; 53 } 54 } 55 printf("%d\n",ans); 56 } 57 return 0; 58 }
数组版,简单对称和谐,以后trie树也这么写:P
难懂的地方就是build函数建trie图,fail[trie[x][i]]=trie[fail[x]][i]保证了后缀相同的性质。pery大爷教育道,当trie[x][i]不存在时直接把它链到trie[fail[x]][i]上来保证复杂度
- 刷模板的时候总会碰到坑B题
hdu2896
1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 100005 4 #define maxc 128 5 char t[255],s[10005]; 6 int tot,num,total,trie[maxn][maxc],vis[510],mark[maxn],fail[maxn],Q[maxn]; 7 void add(char *t,int id){ 8 int p=0; 9 for(int i=1;t[i];i++){ 10 if(!trie[p][t[i]-32])trie[p][t[i]-32]=++tot; 11 p=trie[p][t[i]-32]; 12 } 13 mark[p]=id; 14 } 15 void build(){ 16 int head=0,tail=0; 17 Q[++tail]=0; 18 while(head<tail){ 19 int x=Q[++head]; 20 for(int i=0;i<128;i++){ 21 if(trie[x][i]){ 22 Q[++tail]=trie[x][i]; 23 fail[trie[x][i]]=x?trie[fail[x]][i]:0; 24 } 25 else trie[x][i]=trie[fail[x]][i]; 26 } 27 } 28 } 29 void solve(char *s,int id){ 30 int p=0; 31 bool flag=false; 32 for(int i=1;s[i];i++){ 33 p=trie[p][s[i]-32]; 34 int pp=p; 35 while(pp){ 36 if(mark[pp]){ 37 flag=true; 38 vis[mark[pp]]=1; 39 } 40 pp=fail[pp]; 41 } 42 } 43 if(flag){ 44 total++; 45 printf("web %d:",id); 46 for(int i=1;i<=500;i++) 47 if(vis[i]){ 48 vis[i]=0; 49 printf(" %d",i); 50 } 51 printf("\n"); 52 } 53 } 54 int main(){ 55 int n; 56 scanf("%d",&n); 57 for(int i=1;i<=n;i++){ 58 scanf("%s",t+1); 59 add(t,i); 60 } 61 build(); 62 scanf("%d",&n); 63 for(int i=1;i<=n;i++){ 64 scanf("%s",s+1); 65 solve(s,i); 66 } 67 printf("total: %d\n",total); 68 return 0; 69 }
R/M了12次,boom,,,于是引发了trie数组第一维开多大的讨论也就是对于给定的数据范围,不同的节点到底有多少个。。。毕竟不是所有题都像usaco某题一样给出了不同的节点的最大个数的
- 前两道都是noip之前为了应付膜你赛做的,觉得自己已经基本掌握,,,然而接下来就要打脸了
bzoj2434
#include<stdio.h> #define maxn 100005 char str[maxn]; int cnt,v[maxn],next[maxn],first[maxn],hav[maxn],hanext[maxn],hafirst[maxn]; int time,tot,trie[maxn][26],q[maxn],fail[maxn],in[maxn],out[maxn],pos[maxn],fa[maxn],ans[maxn],BIT[maxn<<1]; void add(int st,int end){ v[++cnt]=end; next[cnt]=first[st]; first[st]=cnt; } void update(int yooo,int x){ for(int i=yooo;i<=time;i+=(i&(-i))) BIT[i]+=x; } int query(int yooo){ int sum=0; for(int i=yooo;i;i-=(i&(-i))) sum+=BIT[i]; return sum; } void build(){ int head=0,tail=0; q[++tail]=0; while(head<tail){ int x=q[++head]; for(int i=0;i<26;i++){ if(trie[x][i]){ q[++tail]=trie[x][i]; fail[trie[x][i]]=x?trie[fail[x]][i]:0; } else trie[x][i]=trie[fail[x]][i]; } } } void dfs(int sss){ in[sss]=++time; for(int e=first[sss];e;e=next[e]) dfs(v[e]); out[sss]=++time; } void solve(){ int p=0,id=0; for(int i=1;str[i];i++){ if(str[i]=='P'){ id++; for(int e=hafirst[id];e;e=hanext[e]){ int lol=pos[hav[e]]; ans[e]=query(out[lol])-query(in[lol]-1); } } else if(str[i]=='B')update(in[p],-1),p=fa[p];// else p=trie[p][str[i]-'a'],update(in[p],1); } } int main(){ freopen("1.in","r",stdin); int m,x,y; scanf("%s",str+1); int p=0,id=0; for(int i=1;str[i];i++){ if(str[i]=='P')pos[++id]=p; else if(str[i]=='B')p=fa[p]; else{ if(!trie[p][str[i]-'a'])trie[p][str[i]-'a']=++tot; fa[trie[p][str[i]-'a']]=p; p=trie[p][str[i]-'a']; } } build(); for(int i=1;i<=tot;i++) add(fail[i],i); dfs(0); scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); hav[i]=x; hanext[i]=hafirst[y]; hafirst[y]=i; } solve(); for(int i=1;i<=m;i++)printf("%d\n",ans[i]); return 0; }
fail树太神,第二个临接表也超美,但是发现自己树状数组和dfs序都不太6的样子,尤其是dfs序,out=++time和out=time的区别还是不卵懂,或者说根本没有区别QAQ
以666结尾,然后去拉车。。。