传送门
思路:
一看到这题第一眼就想到了字典树,很明显需要将字符串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; }