zoukankan      html  css  js  c++  java
  • AC自动机

    P5357 【模板】AC自动机(二次加强版)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+7;
    const int M=2e6+7;
    char s[N],S[M];
    int cnt,tot,to[N],ans[N],du[N];
    struct node{
    	int fail,end,ch[27];
    }t[N];
    inline void insert(char *str){
    	int now=0;
    	int len=strlen(str);
    	for(int i=0;i<len;i++){
    		if(!t[now].ch[str[i]-'a'+1])
    			t[now].ch[str[i]-'a'+1]=++cnt;
    		now=t[now].ch[str[i]-'a'+1];//构造 trie 树
    	}
    	++tot;
    	if(t[now].end) to[tot]=t[now].end;
    	if(!t[now].end) t[now].end=tot;
    }
    queue <int> q;
    int num[N];
    void build(){
    	for(int i=1;i<=26;i++)
    		if(t[0].ch[i]){
    			t[t[0].ch[i]].fail=0;
    			q.push(t[0].ch[i]);
    		}
    	while(q.size()){//bfs 求出失配指针,指向的其实就是他的最大真后缀
    		int now=q.front();
    		q.pop();
    		for(int i=1;i<=26;i++){
    			if(t[now].ch[i]){
    				t[t[now].ch[i]].fail=t[t[now].fail].ch[i];
    				q.push(t[now].ch[i]);
    				du[t[t[now].ch[i]].fail]++;
    			}
    			else t[now].ch[i]=t[t[now].fail].ch[i];
    		}
    	}
    }
    void query(char *str){
    	int now=0;
    	int len=strlen(str);
    	for(int i=0;i<len;i++){
    		now=t[now].ch[str[i]-'a'+1];
    		num[now]++;
    	}
    }
    void topu(){
    	for(int i=1;i<=cnt;i++)//复杂度正确的 trie 树使用方式
    		if(!du[i]) q.push(i);
    	while(q.size()){
    		int now=q.front();
    		q.pop();
    		ans[t[now].end]=num[now];
    		num[t[now].fail]+=num[now];
    		if(!(--du[t[now].fail])) q.push(t[now].fail);
    	}
    }
    int main(){
    	int n;
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		scanf("%s",s);
    		insert(s);
    	}
    	build();
    	scanf("%s",S);
    	query(S);
    	topu();
    	for(int i=1;i<=n;i++){
    		if(!to[i]) printf("%d
    ",ans[i]);
    		else printf("%d
    ",ans[to[i]]);
    	}
    	return 0;
    }
    

    P3966 [TJOI2013]单词

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+7;
    char s[N];
    int cnt,tot,to[N],num,du[N];
    int sz[N],pos[N];
    struct node{
    	int fail,end,ch[27];
    }t[N];
    inline void insert(char *str){
    	int now=0;
    	int len=strlen(str);
    	for(int i=0;i<len;i++){
    		if(!t[now].ch[str[i]-'a'+1])
    			t[now].ch[str[i]-'a'+1]=++cnt;
    		now=t[now].ch[str[i]-'a'+1];
    		sz[now]++;
    	}
    	++tot;//看对于AC自动机建出来的trie图的理解
    	pos[tot]=now;
    }
    queue <int> q;
    void build(){
    	for(int i=1;i<=26;i++)
    		if(t[0].ch[i]){
    			t[t[0].ch[i]].fail=0;
    			q.push(t[0].ch[i]);
    		}
    	while(q.size()){
    		int now=q.front();
    		q.pop();
    		du[++num]=now;
    		for(int i=1;i<=26;i++){
    			if(t[now].ch[i]){
    				t[t[now].ch[i]].fail=t[t[now].fail].ch[i];
    				q.push(t[now].ch[i]);
    			}
    			else t[now].ch[i]=t[t[now].fail].ch[i];
    		}
    	}
    }
    int n;
    void query(){
    	for(int i=cnt;i>=0;i--) sz[t[du[i]].fail]+=sz[du[i]];//这里按照bfs的顺序更新的,如果把A作为fail的点B有贡献的话,A作为B的最大后缀也一定有贡献,所以可以这样处理
        for(int i=1;i<=n;i++) printf("%d
    ",sz[pos[i]]);
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		scanf("%s",s);
    		insert(s);
    	}
    	build();
    	query();
    	return 0;
    }
    
  • 相关阅读:
    java集合 stream 相关用法(1)
    ICE新手入门版
    spring中关于FeignClient的错误 QueryParam.value() was empty on parameter 1
    Java Base64解析
    Java RSA加密以及验签
    项目拆分子工程(简单版)
    mysql "ON DUPLICATE KEY UPDATE" 的使用
    关于多定时任务开发
    AtomicInteger保证线程安全的全局变量
    C++矩阵库 Eigen 快速入门
  • 原文地址:https://www.cnblogs.com/Hikigaya/p/11931194.html
Copyright © 2011-2022 走看看