HDU 2846 Repository (字典树)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846

题意就是输入n个字符串,再输入m个字符串查询,每次问前面n个字符串中,有几个字符串的子串有当前查询的字符串。

思路很简单,先建字典树,每个字符串以不同前缀全部插入,然后对每个节点进行计数,记录当前前缀有几个字符串,查询的时候输出。但是有一个问题,就是一个字符串bb存在两个b作为子串,但是计数的时候只记一次,这个要怎么解决?

解决方法是,在节点内增加一个变量记录,上一次到达这里的单词是第几次,如果当前次与上次相同,说明来源于同一个字符串,就不进行计数。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<cstring>
#include<string>
#include<cctype>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<sstream>
#include<algorithm>
using namespace std;
const int INF=1e9+7;
typedef pair<int,int> pii;
typedef long long ll;
struct trie{
    int next[26];
    int cnt,pre;
}tree[2200000];
int n,m;
int vis=0;
void Insert(char s[],int c){
    int root=0;
    for(int i=0;s[i];i++){
        if(tree[root].next[s[i]-'a']){
            root=tree[root].next[s[i]-'a'];
        }
        else{
            root=tree[root].next[s[i]-'a']=++vis;
        }
        if(tree[root].pre!=c)tree[root].cnt++;
        tree[root].pre=c;
    }
}
int query(char s[]){
    int root=0;
    for(int i=0;s[i];i++){
        if(!tree[root].next[s[i]-'a'])return 0;
        root=tree[root].next[s[i]-'a'];
    }
    return tree[root].cnt;
}
int main(){
//    freopen("D://input.txt","r",stdin);
    scanf("%d",&n);
    while(n--){
        char s[25];scanf("%s",s);
        for(int i=0;s[i];i++){
            Insert(s+i,n);
        }
    }
    scanf("%d",&m);
    while(m--){
        char s[25];scanf("%s",s);
        printf("%d\n",query(s));
    }
    return 0;
}


你可能感兴趣的:(HDU 2846 Repository (字典树))