2018 计蒜之道 初赛 第二场 B 阿里巴巴的手机代理商(简单)[ 字典树 ]


阿里巴巴的手机代理商正在研究 infra 输入法的新功能。他们需要分析单词频率以改进用户输入法的体验。于是需要你在系统内核里面写一个 API。 API 有如下功能:

  1. 添加操作

    添加操作格式为insert barty 8,意思为插入barty这个单词,这个单词词频为 88 次。注意如果再次添加insert barty 8操作时,就会将词频增加为 1616 次。(不会出现词频 \le 00 的情况)。

  2. 删除操作

    删除操作格式为delete barty,意思为删除所有barty这个单词。

    如果当前没有删除的词汇,输出Empty

  3. 查询操作

    查询操作格式为query ty,意思为查询当前版本以ty结尾的单词词频总和。

输入格式

第一行读入一个整数 T,代表数据组数。

每组数据的第一行读入一个整数 N代表操作数。

接下来 N行,每行形容一个操作。

保证数据满足 1 T 10 1000insert操作的字符串总长度之和 3000,所有字符串长度 10000,输入只有小写字母。

输出格式

输出题目中要求的结果。

样例输入

1
6
insert barty 8
query ty
insert party 9
query ty
delete barty
query ty

样例输出

8
17
9

题目来源

2018 计蒜之道 初赛 第二场

思路:线段树的模板题目,就是删除的时候用map存一下出现次数就好了,记得每次要清零哦!!!

代码:

#include<bits/stdc++.h>
#include<iostream>
#include<string>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
const int maxn = 1e6+7;

int trie[maxn][27], tot = 0, t, n;
ll sum[maxn];                         //保存前缀出现的次数
map<string, ll> mp;


void insert(string s)                 //插入单词s
{
    ll p; scanf("%lld", &p);
    mp[s] += p;
    int len = s.length(), root = 0;    //根节点编号为0;
    for(int i = len - 1; i >= 0; i--) {
        int id = s[i] - 'a';           //第一种编号j
        if(!trie[root][id])            //如果之前没有root到id的前缀
            trie[root][id] = ++tot;    //插入,tot即为第一种编号
        root = trie[root][id];         //顺着字典树往下走
        sum[root] += p;                   //前缀后一个位置保存前缀出现的次数;
    }
}

void deletes(string s)
{
    ll p;
    if(mp.count(s) == 0) {
        puts("Empty");
        return;
    }
    if(mp[s] == 0) {
        puts("Empty");
        return;
    }
    p = mp[s]; mp[s] = 0;
    int len = s.length(), root = 0;    //根节点编号为0;
    for(int i = len - 1; i >= 0; i--) {
        int id = s[i] - 'a';           //第一种编号j
        root = trie[root][id];         //顺着字典树往下走
        sum[root] -= p;                //前缀后一个位置保存前缀出现的次数;
    }
}


ll rsearch(string s) {
    int len = s.length(), root = 0;    //从跟节点开始查找;
    for(int i = len - 1; i >= 0; i--) {
        int id = s[i] - 'a';
        if(!trie[root][id]) return 0;     //从root到id的前缀不存在,返回false
        root = trie[root][id];                //为查询下一个字母,顺着字典树往下走
    }
    return sum[root];       //前缀后一个位置保存前缀出现的次数;返回值需改为int;
}

int main()
{
    string a, b;
    //freopen("in.txt", "r", stdin);
    scanf("%d",&t);
    while(t--)
    {
        mp.clear();
        memset(trie, 0, sizeof(trie));
        memset(sum, 0, sizeof(sum));
        scanf("%d",&n);
        while(n--)
        {
            cin >> a >> b;
            if(a == "insert") insert(b);
            else if(a == "delete") deletes(b);
            else printf("%lld\n", rsearch(b));
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_39792252/article/details/80349943
今日推荐