题目描述
在一个 Minecraft 村庄中,村长有这一本小写字母构成的名册(字符串的表),
每个名字旁边都记录着这位村民的声望值,而且有的村民还和别人同名。
随着时间的推移,因为没有村民死亡,这个名册变得十分大。
每个名字旁边都记录着这位村民的声望值,而且有的村民还和别人同名。
随着时间的推移,因为没有村民死亡,这个名册变得十分大。
现在需要您来帮忙维护这个名册,支持下列 4 种操作:
1. 插入新人名 s
i,声望为 a
i
2. 给定名字前缀 p i 的所有人的声望值变化 d i
3. 查询名字为 s j 村民们的声望值的和(因为会有重名的)
4. 查询名字前缀为 p j 的声望值的和
2. 给定名字前缀 p i 的所有人的声望值变化 d i
3. 查询名字为 s j 村民们的声望值的和(因为会有重名的)
4. 查询名字前缀为 p j 的声望值的和
输入描述:
第一行为两个整数 0 ≤ N ≤ 105,表示接下来有 N 个操作; 接下来 N 行,每行输入一个操作,行首为一个整数 1 ≤ oi ≤ 4,表示这一行的操作的种类,
那么这一行的操作和格式为:
1. 插入人名,这一行的格式为 1 s
i a
i,其中 |a
i| ≤ 10
32. 前缀修改声望,这一行的格式为 2 p
i d
i,其中 |d
i| ≤ 10
33. 查询名字的声望和,这一行的格式为 3 s
j4. 查询前缀的声望和,这一行的格式为 4 p
j
输入保证插入人名的字符串的长度和小于或等于 10
5,总的字符串的长度和小于或等于 10
6。
输出描述:
对于每一次询问操作,在一行里面输出答案。
示例1
输入
20 1 a -10 1 abcba -9 1 abcbacd 5 4 a 2 a 9 3 aadaa 3 abcbacd 4 a 3 a 2 a 10 3 a 2 a -2 2 d -8 1 ab -2 2 ab -7 1 aadaa -3 4 a 3 abcba 4 a 4 c
输出
-14 0 14 13 -1 9 11 1 11 0
题目一看就知道是字典树,本来因为刚看了FZU的所以认为是字典树+树状数组维护,其实不用,只需要定时dfs更新下一层,这让我想起了并行计算。。。
代码:
#include<iostream> #include<string> #include<algorithm> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int maxn = 1e6+7; ll trie[maxn][27], tot = 0, sum[maxn], te[maxn], tg[maxn]; //trie表示字典树,tot表示树上的结点,sum[i]表示前缀为p[i]的声望和;te[i] 表示前缀出现的次数; //tg[i]用来辅助第二个操作记录修改,使用的时候再刷新。。 void dfs(int x) { for(int i = 0; i < 26; i++) if(trie[x][i]) tg[trie[x][i]] += tg[x]; sum[x] += tg[x] * te[x]; tg[x] = 0; } void insert(string s, int a) { int len = s.length(), root = 0; for(int i = 0; i < len; i++) { int id = s[i] - 'a'; if(!trie[root][id]) trie[root][id] = ++tot; root = trie[root][id]; dfs(root); sum[root] += a; te[root]++; } } void op2(string s, int a) { int len = s.length(), root = 0; bool f = true; for(int i = 0; i < len; i++) { int id = s[i] - 'a'; if(!trie[root][id]) { f = false; break; } root = trie[root][id]; dfs(root); } if(f) { tg[root] += a; int re = te[root]; root = 0; for(int i = 0; i < len - 1; i++) root = trie[root][s[i] - 'a'], sum[root] += re*a; } } ll op4(string s) { int len = s.length(), root = 0; bool f = true; for(int i = 0; i < len; i++) { int id = s[i] - 'a'; if(!trie[root][id]) { f = false; break; } root = trie[root][id]; dfs(root); } if(f) return sum[root]; else return 0; } ll op3(string s) { int len = s.length(), root = 0; bool f = true; for(int i = 0; i < len; i++) { int id = s[i] - 'a'; if(!trie[root][id]) { f = false; break; } root = trie[root][id]; dfs(root); } if(f) { ll ans = 0; for(int i = 0; i < 26; i++) if(trie[root][i]) { dfs(trie[root][i]); ans += sum[trie[root][i]]; } return (sum[root] - ans); } else return 0; } int main() { //freopen("into.txt","r",stdin); int n; string s; memset(trie, 0, sizeof(trie)); memset(sum, 0, sizeof(sum)); memset(vis, 0, sizeof(vis)); memset(tg, 0, sizeof(tg)); memset(te, 0, sizeof(te)); scanf("%d", &n); while(n--) { int op, a; cin >> op; if(op == 1) { cin >> s >> a; insert(s, a); } else if(op == 2) { cin >> s >> a; op2(s, a); } else if(op == 4) { cin >> s; cout << op4(s) << endl; } else { cin >> s; cout << op3(s) << endl; } } //fclose(stdin); return 0; }
我水平低,欢迎大佬指正。。。。。