在一个 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 ≤ 10
5
,表示接下来有 N 个操作;
接下来 N 行,每行输入一个操作,行首为一个整数 1 ≤ o
i
≤ 4,表示这一行的操作的种类,
那么这一行的操作和格式为:
1. 插入人名,这一行的格式为 1 s
i a
i,其中 |a
i| ≤ 10
3
2. 前缀修改声望,这一行的格式为 2 p i d i,其中 |d i| ≤ 10 3
3. 查询名字的声望和,这一行的格式为 3 s j
4. 查询前缀的声望和,这一行的格式为 4 p j
2. 前缀修改声望,这一行的格式为 2 p i d i,其中 |d i| ≤ 10 3
3. 查询名字的声望和,这一行的格式为 3 s j
4. 查询前缀的声望和,这一行的格式为 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
题意 : 直接看题干就行了,是一个带前缀修改的字典树
思路分析 : 正常的字典树,加一个前缀修改的懒标记就可以了
代码示例 :
#define ll long long
const ll maxn = 1e6+5;
const ll mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const ll inf = 0x3f3f3f3f;
char s[maxn];
ll n, d;
ll ch[3*maxn][26];
ll sz = 1;
ll val[3*maxn];
ll lazy[3*maxn];
ll cnt[3*maxn];
void pushdown(ll k){
for(ll i = 0; i < 26; i++){
if (ch[k][i] != 0){
ll u = ch[k][i];
lazy[u] += lazy[k];
val[u] += cnt[u]*lazy[k];
}
}
lazy[k] = 0;
}
void insert(){
ll u = 0, c;
ll last;
for(ll i = 0; i < strlen(s); i++){
c = s[i]-'a';
if (lazy[u]) pushdown(u);
if (!ch[u][c]) ch[u][c] = sz++;
u = ch[u][c];
val[u] += d;
cnt[u]++;
}
}
void update(){
ll u = 0, c;
ll last;
for(ll i = 0; i <strlen(s); i++){
c = s[i]-'a';
last = u;
if (!ch[u][c]) return;
u = ch[u][c];
}
ll num = cnt[u];
u = 0;
for(ll i = 0; i <strlen(s); i++){
c = s[i]-'a';
if (lazy[u] != 0) pushdown(u);
u = ch[u][c];
val[u] += d*num;
}
lazy[u] += d;
}
ll query3(ll k){
ll sum = 0;
for(ll i = 0; i < 26; i++){
if (ch[k][i] != 0){
if (lazy[ch[k][i]] != 0) pushdown(ch[k][i]);
sum += val[ch[k][i]];
}
}
return sum;
}
ll query1(){
ll u = 0, c;
for(ll i = 0; i < strlen(s); i++){
c = s[i]-'a';
if (lazy[u] != 0) pushdown(u);
if (!ch[u][c]) return 0;
u = ch[u][c];
}
if (lazy[u]) pushdown(u);
ll sum = val[u]-query3(u);
return sum;
}
ll query2(){
ll u = 0, c;
for(ll i = 0; i < strlen(s); i++){
c = s[i]-'a';
if (lazy[u] != 0) pushdown(u);
if (!ch[u][c]) return 0;
u = ch[u][c];
}
return val[u];
}
int main() {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
ll t;
cin >> t;
while(t--){
scanf("%lld%s", &n, s);
if (n == 1){
scanf("%lld", &d);
insert();
}
else if (n == 2) {scanf("%lld", &d); update();}
else if (n == 3) printf("%lld\n", query1());
else printf("%lld\n", query2());
}
return 0;
}