Wannafly挑战赛14 B(字典树的lazy标记)

链接: https://www.nowcoder.com/acm/contest/81/B
来源:牛客网

题目描述

在一个 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 3 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
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int N = 1E5 + 7;

ll sum[N]; //当前节点的前缀和
int cnt_num[N];//某个单词出现的次数
ll a[N]; //某个单词当前价值
int tag[N]; //标记,表示i以及i下面的每个数实际为num-tag[i]
int sz[N];
char s[N];
int tot;
int tree[N][26];

void insert(char *s, int d)
{
    int n = strlen(s);
    int now = 0;
    int w = d;
    for(int i = 0;i < n;i ++) {
        int key = s[i] - 'a';
        if(tree[now][key] == 0) tree[now][key] = ++tot;
        now = tree[now][key];
        w -= tag[now];
        sum[now] += w;
        sz[now] ++;
    }
    cnt_num[now] ++;
    a[now] += w;
}

void update(char *s, int d)
{
    int n = strlen(s);
    int now = 0;
    for(int i = 0;i < n;i ++) {
        int key = s[i] - 'a';
        if(tree[now][key] == 0) return;
        now = tree[now][key];
    }
    tag[now] += d;
    d = sz[now] * d;
    int tnow = now;
    now = 0;
    for(int i = 0;i < n;i ++) {
        int key = s[i] - 'a';
        now = tree[now][key];
        if(now != tnow) sum[now] += d;
    }
}

ll query1(char *s)
{
    int n = strlen(s);
    int now = 0;
    ll det = 0;
    for(int i = 0;i < n;i ++) {
        int key = s[i]-'a';
        now = tree[now][key];
        if(now == 0) return 0;
        det += tag[now];
    }
    if(!cnt_num[now]) return 0;
    return cnt_num[now] * 1ll * det + a[now];
}

ll query2(char *s)
{
    int n = strlen(s);
    int now = 0;
    ll det = 0;
    for(int i = 0;i < n;i ++) {
        int key = s[i]-'a';
        now = tree[now][key];
        if(now == 0) return 0;
        det += tag[now];
    }
    return sz[now] * 1ll * det + sum[now];
}


int main()
{
    //freopen("f:\\out.txt","w",stdout);
    int q;
    scanf("%d", &q);
    while(q --) {
        int opt, d;
        scanf("%d %s", &opt, s);
        if(opt == 1) {
            scanf("%d", &d);
            insert(s, d);
        } else if(opt == 2) {
            scanf("%d", &d);
            update(s, d);
        } else if(opt == 3) {
            printf("%lld\n", query1(s));
        } else {
            printf("%lld\n", query2(s));
        }
    }
    return 0;
}










猜你喜欢

转载自blog.csdn.net/qq_36876305/article/details/80061462