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结尾,然后去拉车。。。

posted @ 2015-11-19 20:35  Ngshily  阅读(156)  评论(0编辑  收藏  举报