HDU 2846(Trie树)

    题面:

Repository

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 6650    Accepted Submission(s): 2143


Problem Description
When you go shopping, you can search in repository for avalible merchandises by the computers and internet. First you give the search system a name about something, then the system responds with the results. Now you are given a lot merchandise names in repository and some queries, and required to simulate the process.
 

Input
There is only one case. First there is an integer P (1<=P<=10000)representing the number of the merchanidse names in the repository. The next P lines each contain a string (it's length isn't beyond 20,and all the letters are lowercase).Then there is an integer Q(1<=Q<=100000) representing the number of the queries. The next Q lines each contains a string(the same limitation as foregoing descriptions) as the searching condition.
 

Output
For each query, you just output the number of the merchandises, whose names contain the search string as their substrings.
 

Sample Input
 
  
20 ad ae af ag ah ai aj ak al ads add ade adf adg adh adi adj adk adl aes 5 b a d ad s
 

Sample Output
 
  
0 20 11 11 2
 

Source
 

    题目描述:先给你P个字符串,再给你Q个字符串,问你这这Q个字符串在P个字符串中出现的次数。
    题面分析:因为这题涉及多个字符串与多个字符串的匹配问题,因此我们可以考虑使用Trie树进行高效的处理。但是需要注意的是,在Trie树的经典题目中,我们只需要判断前缀是否符合即可,但是在这道题上,并没有前缀的限制(即只要出现了即可)。因此我们需要考虑对Trie树进行一定的变形。
   考虑到P个模板串的大小和Q个匹配串的大小最多也才20,因此,我们可以考虑将每个模板串中所对应的字串都一一插入到Trie树即可(但是此时需要注意,因为某些字串可能是相同的,如匹配串abc与abd就有字串ab是相同的,因此还得加入标记数组进行标记去重)
    最后只需要对每个匹配串进行查询即可得出答案了

    
    代码如下:
#include <bits/stdc++.h>
#define maxn 500005
using namespace std;
struct Trie{
    int trie[maxn][26];
    int val[maxn];
    int flag[maxn];
    int sz;
    void init(){
        memset(trie,0,sizeof(trie));
        memset(val,0,sizeof(val));
        memset(flag,-1,sizeof(flag));
        sz=1;
    }
    void Insert(string str,int x){
        int i,len=str.length();
        int u=0;
        for(int i=0;i<len;i++){
            int c=str[i]-'a';
            if(trie[u][c]==0) trie[u][c]=sz++;
            u=trie[u][c];
        }
        if(flag[u]!=x){
            val[u]++;
            flag[u]=x;
        }
    }
    int Search(string str){
        int i,len=str.length();
        int u=0;
        for(int i=0;i<len;i++){
            int c=str[i]-'a';
            if(!trie[u][c]){
                return 0;
            }
            u=trie[u][c];
        }
        return val[u];
    }
}tree;
int main()
{
    //freopen("in.txt","r",stdin);
    tree.init();
    int n,m,i;
    cin>>n;
    string str;
    while(n--){
        cin>>str;
        int len=str.length();
        for(int i=0;i<len;i++){
            for(int j=1;j<len-i+1;j++){
                tree.Insert(str.substr(i,j),n);
            }
        }
    }
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>str;
        cout<<tree.Search(str)<<endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值