C. 阿里巴巴的手机代理商 (字典树)

  • 8.81%
  •  3000ms
  •  524288K

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

  1. 添加操作

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

  2. 删除操作

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

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

  3. 查询操作

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

  4. 修改操作

    修改操作格式为update ty tied,意思为将所有结尾是ty的单词更新为tied结尾,比如barty会变为bartied。如果不存在ty结尾的单词,输出Empty。如果已经存在tied结尾的单词,那么说明存在 conflict。 不做合并,输出Conflict。如果既不存在ty结尾的单词,也已经存在以tied结尾的单词,则输出Empty

输入格式

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

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

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

保证数据满足 1 \le T \le 101T101 \le N \le 10^51N105insertupdate操作的字符串总长度之和 \le 10^6106,所有字符串长度 \le 10^6106,输入只有小写字母。

输出格式

输出题目中要求的结果。

样例输入

1
10
update y ty
insert barty 8
delete shawn
update ty tied
query tied
insert party 9
update y tied
query ty
delete barty
query tied

样例输出

Empty
Empty
8
Conflict
9
Empty
8

题解:把单词反转之后用Trie操作即可~~ 字典树每一个节点代表的字符信息由其在父节点的位置决定。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,n) for(int i=(a);i<(n);++i)
#define per(i,a,n) for(int i=(n-1);i>=(a);--i)
#define pb push_back
const int Inf=1e9;
#define N 1000010
#define M 26
int ch[N][M],tot;
ll sum[N];
void Insert(string str,int num){
    int rt=0;             //根节点
    for(int i=0;i<str.length();++i){
        int id=str[i]-'a';
        if(!ch[rt][id]){      //添加新的子树
            ch[rt][id]=++tot;   //子树下标
            for(int j=0;j<M;++j){   //初始化子树节点以及初始sum值
                ch[tot][j]=0;
            }
            sum[tot]=0;
        }
        rt=ch[rt][id];   //进入子树
        sum[rt]+=num;    //更新子树值
    }
}
ll Query(string str){   //以str为前缀的单词数目,(因为已经反转单词,其实是找后缀相同)
    int rt=0;
    for(int i=0;i<str.length();++i){
        int id=str[i]-'a';
        if(!ch[rt][id]){
            return 0;
        }
        rt=ch[rt][id];
    }
    return sum[rt];
}
bool Delete(string str){
    int rt=0;
    for(int i=0;i<str.length();++i){
        int id=str[i]-'a';
        if(!ch[rt][id]){
            return 0;
        }
        rt=ch[rt][id];
    }
    ll num=sum[rt];
    for(int i=0;i<M;++i){   //去除以str为前缀的单词
        if(ch[rt][i]){
            num-=sum[ch[rt][i]];
        }
    }
    if(!num) return false;
    Insert(str,-1*num);
    return true;
}
int Get(string str,ll num){    //把str删除,此处只把值更改
    int rt=0,len=str.length();
    for(int i=0;i<len-1;++i){
        int id=str[i]-'a';
        sum[ch[rt][id]]-=num;
        rt=ch[rt][id];
    }
    int index=ch[rt][str[len-1]-'a']; //取出要删除字符串末尾位的下标,把这个节点连接作为到更改后的字符串末尾位
    ch[rt][str[len-1]-'a']=0;  //沿着str路径不再能访问末尾节点,(下标置为空)
    return index;
}
void Link(string str,int index,ll num){
    int rt=0,len=str.length();
    for(int i=0;i<len-1;++i){
        int id=str[i]-'a';
        if(!ch[rt][id]){
            ch[rt][id]=++tot;
            for(int j=0;j<M;++j) ch[tot][j]=0;
            sum[tot]=0;
        }
        rt=ch[rt][id];
        sum[rt]+=num;
    }
    ch[rt][str[len-1]-'a']=index; //沿着新的路径,可以访问更改前的末尾位,以及后续子节点
}
int main(){
    ios::sync_with_stdio(0);
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        string op;
        string str1,str2;
        ll num;
        tot=0;
        for(int i=0;i<M;++i) ch[tot][i]=0;
        while(n--){
            cin>>op;
            if(op[0]=='i'){
                cin>>str1>>num;
                reverse(str1.begin(),str1.end());
                Insert(str1,num);
            }
            else if(op[0]=='d'){
                cin>>str1;
                reverse(str1.begin(),str1.end());
                bool flag=Delete(str1);
                if(!flag) cout<<"Empty"<<endl;
            }
            else if(op[0]=='q'){
                cin>>str1;
                reverse(str1.begin(),str1.end());
                cout<<Query(str1)<<endl;
            }
            else if(op[0]=='u'){
                cin>>str1>>str2;
                reverse(str1.begin(),str1.end());
                reverse(str2.begin(),str2.end());
                num=Query(str1);
                if(!num){
                    cout<<"Empty"<<endl;
                }
                else{
                    if(Query(str2)){
                        cout<<"Conflict"<<endl;
                    }
                    else{
                        int index=Get(str1,num);
                        Link(str2,index,num);
                    }
                }
            }
        }
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/u011721440/article/details/80324356
今日推荐