题目描述
在一个 Minecraft 村庄中,村长有这一本小写字母构成的名册(字符串的表),
每个名字旁边都记录着这位村民的声望值,而且有的村民还和别人同名。
随着时间的推移,因为没有村民死亡,这个名册变得十分大。
现在需要您来帮忙维护这个名册,支持下列 4 种操作: 1. 插入新人名 s
i,声望为 a
i
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;
}
我水平低,欢迎大佬指正。。。。。