hdu 2846 Repository 字典树

//	hdu 2846 Repository 字典树
//
//	题目大意:
//		
//		有n个字符串,m个待询问的字符串,问这些字符串里面以该询问的
//		字符串为子串的字符串有多少个
//
//	解题思路:
//		
//		字典树,将字符串的所有子串插入到字典树中,并设立一个No.标识
//		以免重计数。最后查询就好了
//
//	感悟:
//		
//		这题的数据量有点大,虽然p是10000,但是长度是20,单个字符串的
//		最大子串数粗略的估计是 20 * 20 ,所以开的空间也要比较大。开始
//		开的是30w,返回了wa,开了40w,还是返回wa,开了50w,结果轻松Ac
//		啦~,继续加油哟~~~FIGHTING
	

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAX_N = 500000;

struct Trie{

	int ch[MAX_N][26];
	int sz;
	int val[MAX_N];
	int no[MAX_N];

	void init(){
		sz = 1;
		memset(ch[0],0,sizeof(ch[0]));
		val[0] = 0;
		no[0] = 0;
	}

	int idx(char c){
		return c - 'a';
	}

	void insert(char *s,int st,int ed,int v){
		int u = 0;
		//int n = strlen(s);
		for (int i=st;i<=ed;i++){
			int c = idx(s[i]);

			if (no[u]!=v)	// 这里是为了不重复计数,如果插入的点
				val[u]++;   // 是当前的串的子串,所有的该串子串都
							// 会有特定的v的标记,碰到了就避免计数

			if (!ch[u][c]){
				memset(ch[sz],0,sizeof(ch[sz]));
				val[sz] = 0;
				no[sz] = 0;
				ch[u][c] = sz++;
			}
			u = ch[u][c];
		}
		if (no[u]!=v)  // 不要忘了在插入的末尾,可能还会有相同的子串诺
			val[u]++;
		no[u] = v;
	}

	int query(char *s){
		int u = 0;
		int n = strlen(s);
		for (int i=0;i<n;i++){
			int c = idx(s[i]);
			if (!ch[u][c]){
				return 0;
			}

			u = ch[u][c];
		}
		return val[u];
	}



}trie;

void print(char *s,int st,int ed,int num){
	printf("%d \n\n",num);
	for (int i=st;i<=ed;i++){
		printf("%c",s[i]);
	}
	cout << endl;
}

int n,m;
bool vis[10009];
void input(){
	trie.init();
	char s[30];
	for (int i=1;i<=n;i++){
		scanf("%s",s);
		int len = strlen(s);
		for (int j=len-1;j>=0;j--){
			for (int k=j;k<len;k++){
				trie.insert(s,j,k,i);
				//print(s,j,k,i);
			}
		}
	}
	scanf("%d",&m);
	for (int i=1;i<=m;i++){
		scanf("%s",s);
		printf("%d\n",trie.query(s));

	}

	//memset(vis,0,sizeof(vis))
	
}

int main(){
	//freopen("1.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		input();
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值