HDU 2846 ac自动机 给定n个串 q个询问 问是n个串中几个串的子串

注意每个串只能成为一个串的子串 only once

所以用set去重


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define ll __int64
#define N 10010  
#define inf 100000000000000
#define maxnode 250001
#define sigma_size 26

struct Trie{
	int ch[maxnode][sigma_size];
	int val[maxnode];	 //该单词在模式串中出现的次数
	int last[maxnode];
	int f[maxnode];		 //失配数组
	int num[maxnode];	 //该单词出现在文本串的次数
	int pre[maxnode];    //该单词的前驱
	int len[maxnode];    //以该单词结尾的单词长度
	int Char[maxnode];	 //该单词对应的字母
	int sz;
	void init(){
		sz=1;
		memset(ch,0,sizeof(ch));
		memset(val, 0, sizeof(val));  
		memset(f,0,sizeof(f));
		memset(last,0,sizeof(last));    //记录该节点前一个节点是谁
		memset(len, 0, sizeof(len));
	}
	int idx(char c){ return c-'a'; }
	int insert(char *s){
		int u = 0;
		for(int i = 0; s[i] ;i++){
			int c = idx(s[i]);
			if(!ch[u][c])
				ch[u][c] = sz++;
			pre[ch[u][c]] = u;
			Char[ch[u][c]] = s[i];
			len[ch[u][c]] = len[u]+1;
			u = ch[u][c];
		}
		val[u] = 1;
		num[u] = 0;
		return u;
	}
   void getFail(){    
        queue q;    
        for(int i = 0; imyset; myset.clear();
		int j = 0;
		for(int i = 0; T[i] ; i++){
			int c = idx(T[i]);
			while(j && ch[j][c]==0) j = f[j];
			j = ch[j][c];

			int temp = j;
			while(temp){ //沿失配边走 || 若沿失配边走时一定要节点为单词结尾则改成while(temp && val[temp])
				if(myset.find(temp)==myset.end()){
					myset.insert(temp);
				num[temp]++;
				}
				temp = f[temp];
			}
		}
	}
}ac;
int Stack[100010];
char s[30], hehe[N][30];
int main(){
	int n, que, i;
	ac.init();
	scanf("%d",&n);
	for(i = 0; i < n; i++)scanf("%s",hehe[i]);
	scanf("%d",&que);
	for(i = 0; i < que; i++){
		scanf("%s",s);
		Stack[i] = ac.insert(s);
	}
	ac.getFail();
	for(i = 0; i < n; i++)ac.find(hehe[i]);
	for(i = 0; i < que; i++)printf("%d\n",ac.num[Stack[i]]);
	return 0;
}


你可能感兴趣的:(AC自动机)