2018计蒜之道 阿里巴巴的手机代理商(中等) 字典树(删除+修改)

传送门

思路:

    一看到这题第一眼就想到了字典树,很明显需要将字符串reverse一下,然后按照对应的操作进行操作就好了。当时主要卡在了如何修改上,其实修改也非常简单,我们只需找到原来后缀的子树,然后将新的后缀插入字典树,最后将原来的子树挂到新的后缀下即可。但是有一点需要注意就是原来的后缀子树并不能删除,只需要把对应层的结点赋值为0即可。记得这个过程需要维护一下替换后的前缀单词数。

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e6+5;
typedef long long ll;
int trie[maxn][30];
ll num[maxn],now;//num数组表示到该单词位置,以该单词为前缀的单词的数量
void insert(string ss,ll kk)
{
    int cur = 0;
    for(int i = 0;i < ss.size();++i)
    {
        int c = ss[i] - 'a';
        if(trie[cur][c] == 0)
        {
            memset(trie[now],0,sizeof trie[now]);
            num[now] = 0;
            trie[cur][c] = now++;
        }
        cur = trie[cur][c];
        num[cur] += kk;
    }
    return ;
}
ll query(string ss)
{
    int cur = 0;
    for(int i = 0;i < ss.size();++i)
    {
        int c = ss[i] - 'a';
        if(trie[cur][c] == 0) return 0;
        cur = trie[cur][c];
    }
    return num[cur];
}
ll ask(string ss)
{
    int cur = 0;
    for(int i = 0;i < ss.size();++i)
    {
        int c = ss[i] - 'a';
        if(trie[cur][c] == 0) return 0;//没有前缀则没有单词
        cur = trie[cur][c];
    }
    ll res = num[cur];//我们这里获得的是以该单词为前缀的单词的数量
    for(int i = 0;i < 26;++i)
        res -= num[trie[cur][i]];//这里需要减掉该单词所有后面的结点,得到该单词的数量
    return res;
}
bool del(string ss)
{
    ll flag = ask(ss);
    if(!flag) return false;
    insert(ss,-flag);
    return true;
}
ll get(string ss)
{
    ll res = query(ss);
    int cur = 0;
    for(int i = 0;i < ss.size() - 1;++i)
    {
        int c= ss[i] - 'a';
        cur = trie[cur][c];
        num[cur] -= res;
    }
    int c = ss[ss.size() - 1] - 'a';
    int rt = trie[cur][c];//得到原来的子树
    trie[cur][c] = 0;//删除该点(即在沿着字典树向下找,该前缀是不存在的)
    return rt;
}
void update(string ss,int cnt)
{
    ll d = num[cnt];//对应的前缀单词数
    int cur = 0;
    for(int i = 0;i < ss.size() - 1;++i)
    {
        int c = ss[i] - 'a';
        if(!trie[cur][c])//插入新后缀
        {
            memset(trie[now],0,sizeof trie[now]);
            num[now] = 0;
            trie[cur][c] = now++;
        }
        cur = trie[cur][c];
        num[cur] += d; //维护前缀单词数
    }
    int c = ss[ss.size() - 1] - 'a';
    trie[cur][c] = cnt;//将原子树挂到新后缀下
    return ;
}
int main()
{
    int _,n;
    cin >> _;
    while(_--)
    {
        now = 1;
        memset(trie[0],0,sizeof trie[0]);
        num[0] = 0;
        scanf("%d",&n);
        while(n--)
        {
            string op,str;
            ll cnt;
            cin >> op >> str;
            reverse(str.begin(),str.end());
            //cout << str << endl;
            if(op == "insert")
            {
                cin >> cnt;
                insert(str,cnt);
            }
            else if(op == "delete")
            {
               int flag = del(str);
               if(!flag) puts("Empty");
            }
            else if(op == "query")
            {
                printf("%lld\n",query(str));
            }
            else
            {
                string rep;
                cin >> rep;
                reverse(rep.begin(),rep.end());
                ll ans1 = query(str);
                ll ans2 = query(rep);
                if(ans1 == 0)
                    puts("Empty");
                else if(ans2)
                    puts("Conflict");
                else
                {
                    int ans = get(str);
                    update(rep,ans);
                }
            }
        }
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/HowardEmily/article/details/80339215
今日推荐