• 带前缀修改的字典树


    在一个 Minecraft 村庄中,村长有这一本小写字母构成的名册(字符串的表),
    每个名字旁边都记录着这位村民的声望值,而且有的村民还和别人同名。
    随着时间的推移,因为没有村民死亡,这个名册变得十分大。
    现在需要您来帮忙维护这个名册,支持下列 4 种操作:
    1. 插入新人名 si,声望为 ai
    2. 给定名字前缀 pi 的所有人的声望值变化 di
    3. 查询名字为 sj 村民们的声望值的和(因为会有重名的)
    4. 查询名字前缀为 pj 的声望值的和

    输入描述:

    第一行为两个整数 0 ≤ N ≤ 10

    5

    ,表示接下来有 N 个操作;
    接下来 N 行,每行输入一个操作,行首为一个整数 1 ≤ o

    i

     ≤ 4,表示这一行的操作的种类,
    那么这一行的操作和格式为:
    1. 插入人名,这一行的格式为 1 si ai,其中 |ai| ≤ 103
    2. 前缀修改声望,这一行的格式为 2 pi di,其中 |di| ≤ 103
    3. 查询名字的声望和,这一行的格式为 3 sj
    4. 查询前缀的声望和,这一行的格式为 4 pj
    输入保证插入人名的字符串的长度和小于或等于 105,总的字符串的长度和小于或等于 106

    输出描述:

    对于每一次询问操作,在一行里面输出答案。
    示例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
    ", query1());
            else printf("%lld
    ", query2());
        }
        return 0;
    }
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    洛谷1280 尼克的任务
    洛谷1140 相似基因
    洛谷1133 教主的花园
    洛谷1130 红牌
    洛谷1122 最大子树和
    洛谷1103 书本整理
    洛谷1077 摆花
    【数学】数学知识习题小结(模板)
    python中的深拷贝和浅拷贝(面试题二)
    python中的深拷贝和浅拷贝(面试题)
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/8926161.html
Copyright © 2020-2023  润新知