HDU_2846 Repository 【字典树】

题目链接

题目描述

给定n个字符串然后再给出m个查询,问每次查询的字符串s是那n个字符串子串的个数。注意如果查询的为ab,存在一个字符串abab,那么在这个abab的字符串中,只能计数1而不是2,也就是说一个字符串只能计数1次。

解题思路

Trie能很快的求出字典中以某个串为前缀的串的个数 但现在要查的是以某个串为子串的串的个数 可以发现
一个串的任何子串肯定是这个串某个后缀的前缀 如”ri”是“Trie” 的子串 是后缀 “rie” 的前缀
那么我们在向Trie中插入时可以把这个串的所有后缀都插入 插入时要注意来自同一个串的后缀的相同前缀只能统计一次 如 “abab” 这个串 “ab” 既是后缀 “abab” 的前缀 也是后缀 “ab” 的前缀 但是只能统计一次 这用一个id数组标记就行了
这样最后Trie中以查询串为前缀的串的个数就是原始串中以查询串为子串的串的的个数了

代码部分

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5e5 + 10;
int nex[maxn][26];
int cnt[maxn], id[maxn];
int top, root, ans;
inline int idx(char c)
{
    return c - 'a';
}
inline void Init()
{
    top = 0;
    memset(nex, 0, sizeof(nex));
    memset(cnt, 0, sizeof(cnt));
    memset(id, 0, sizeof(id));
    root = top ++;
}
void Insert(string s, int x)
{
    int len = s.size();
    int now = root;
    for(int i = 0; i < len; ++ i)
    {
        int temp = idx(s[i]);
        if(!nex[now][temp]) nex[now][temp] = top ++;
        now = nex[now][temp];
        if(id[now] != x) cnt[now] ++;
        id[now] = x;
    }
}
int Search(string s)
{
    int now = root;
    int len = s.size();
    for(int i = 0; i < len; ++ i)
    {
        int temp = idx(s[i]);
        if(!nex[now][temp]) return 0;
        now = nex[now][temp];
    }
    return cnt[now];
}
int main()
{
    ios::sync_with_stdio(false);
    int n; string s;
    cin >> n;
    Init();
    for(int i = 1; i <= n; ++ i)
    {
        cin >> s;
        for(int j = 0; j < s.size(); ++ j)
        {
            string c = s;
            c.erase(c.begin(), c.begin() + j);
            Insert(c, i);
        }
    }
    cin >> n;
    while(n --)
    {
        cin >> s;
        cout << Search(s) << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值