百度之星 2016资格赛 Problem C

本文探讨了在经典字典树基础上增加删除操作的实现细节,并通过实例展示了如何利用字典树的特性进行高效操作。文章深入分析了删除操作对字典树结构的影响,包括节点数量变化及路径优化,提供了实际应用中的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5687

此题比起经典的字典树问题多了一个删除的选项,关于删除选项,我们只需要记录每一位的之前前缀出现的次数,当我们删除的前缀出现时,我们把这个要删除的后面的所有子节点删掉,然后前面每一位的出现次数减去前缀出现的次数。为什么要这么做呢,因为我们是要删除所有以这个为前缀的单词,所以在删除后缀的时候,我们有可能也会删掉前缀,比如insert aaaa delete aaa search aa,这组数据我们在删除aaa后,所有的都没了,再比如insert aaab insert aab delete aaa search aa,这组我们只会删掉aaab这个单词,很明显我们可以通过出现的次数来判断是否可以删掉前缀前面的节点。

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 1e5 + 5;
char oper[10];
char str[35];
const int NODE = N * 30;
int tree[NODE][26], val[NODE];
int sz;
void clear()
{
    memset(tree[0],0,sizeof (tree[0]));
    sz = 1;
}
int idx(char c)
{
    return c - 'a';
}
void insertTrie(char *s)
{
    int u = 0;
    for(int c, i=0; s[i]; ++i)
	{
        c = idx(s[i]);
        if(!tree[u][c])
		{
            memset(tree[sz],0,sizeof(tree[sz]));
            val[sz] = 0;
            tree[u][c] = sz++;
        }
        u = tree[u][c];
        val[u]++;
    }
}
void deleteTrie(char *s, int num)
{
    int u = 0;
    for(int c, i=0; s[i]; ++i)
	{
        c = idx(s[i]);
        u = tree[u][c];
        val[u] -= num;
    }
    memset(tree[u], 0, sizeof(tree[u]));
}
int searchTrie(char *t)
{
    int u = 0;
    for(int c, i=0; t[i]; ++i)
	{
        c = idx(t[i]);
        if(!tree[u][c]) return 0;
        u = tree[u][c];
    }
    return val[u];
}
int main()
{
    int n;
    while(scanf ("%d", &n) == 1)
	{
        clear();
        for(int i=0; i<n; ++i)
		{
            scanf ("%s%s", oper, str);
            if(oper[0] == 'i')
                insertTrie(str);
			else if(oper[0] == 'd')
			{
                int cnt = searchTrie(str);
                if(cnt > 0)
                    deleteTrie(str, cnt);
            }
			else
			{
                int cnt = searchTrie(str);
                if(cnt > 0)
                    puts("Yes");
                else
                    puts("No");
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值