带前缀修改的字典树

在一个 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\n", query1());
        else printf("%lld\n", query2());
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ccut-ry/p/8926161.html

时间: 2024-10-13 19:01:41

带前缀修改的字典树的相关文章

# 前缀统计~[字典树]

前缀统计~[字典树] 传送门 题意 给出N个字符串,进行M次询问,每次给出一个字符串,询问N个字符串中有多少个是它的前缀. 思路 字典树Trie入门题. 字典树最典型的应用就是用来存储字符串. 其中每个节点下有26个子节点(对应26个字母),根据新建节点的顺序使用idx为节点编号,根节点和空节点编号都为0,每个叶节点维护一个cnt,标记以这个叶节点结尾的字符串有几个. 使用这种存储方式可以很容易查找一个字符串是否存在,以及出现过几次等等. Code: #include <bits/stdc++.

[BZOJ1590] [Usaco2008 Dec]Secret Message 秘密信息(字典树)

传送门 看到前缀就要想到字典树! 看到前缀就要想到字典树! 看到前缀就要想到字典树! #include <cstdio> #include <iostream> #define N 500001 int n, m, k, cnt; int a[N], val[N], num[N], next[N][2]; inline int read() { int x = 0, f = 1; char ch = getchar(); for(; !isdigit(ch); ch = getch

Phone List HDU - 1671 字典树

题意:给出一堆一组一组的数字  判断有没有哪一个是另外一个的前缀 思路:字典树 插入的同时进行判断  不过 当处理一组数字的时候 需要考虑的有两点1.是否包含了其他的序列2.是否被其他序列包含 刚开始开的1e4死活不过  1e5直接过了.. 1 #include<bits/stdc++.h> 2 #include<string> 3 using namespace std; 4 const int maxn=1e5+5; 5 struct Trie{ 6 int size; 7 i

字典树的建立和基本查找

字典树的建立和基本查找 一.字典树的定义 字典树又叫做前缀树,任意一个或多个字符串可以构建一棵字典树用于存储多个串的公共前缀 二.构建字典树的两种方法 (1)字典树的链表构建及查找 在用链表构造的字典树中每一个节点有着一个数据域来存放该点代表的字符和26个指针分别指向a(A)~z(Z)26个可能出现的子字符,在寻找某个字符串是否出现时,从根节点出发不断向下查找配对,如果到了最后一个字符都存在则表示该前缀存在 (2)字典树的二维数组构建及查找 用二维数组tree[i][j]来标识一颗字典树,其中i

【字符串算法】字典树Trie入门

基本概念 顾名思义,字典树(也叫前缀树)就是可以像字典那样来保存一些单词的集合. 如图所示: (图片来自OIWiKi) 设根节点的标号为$0$,然后其余结点依次编号:我们用数组来存每个节点的所有子节点 更具体地,设数组$ch[MaxNode][SigmaSize]$,其中$MaxNode$表示最大可能的节点个数,$SigmaSize$是字符集合.$ch[i][j]$表示结点标号为$i$的结点 的 字母编号为$j$(比如说,j=字母-'a')的子节点的结点标号.如果$ch[i][j]$为$0$,则

P4551 最长异或路径 (01字典树,异或前缀和)

题目描述 给定一棵 nn 个点的带权树,结点下标从 11 开始到 NN .寻找树中找两个结点,求最长的异或路径. 异或路径指的是指两个结点之间唯一路径上的所有边权的异或. 输入输出格式 输入格式: 第一行一个整数 NN ,表示点数. 接下来 n-1n?1 行,给出 u,v,wu,v,w ,分别表示树上的 uu 点和 vv 点有连边,边的权值是 ww . 输出格式: 一行,一个整数表示答案. 输入输出样例 输入样例#1: 4 1 2 3 2 3 4 2 4 6 输出样例#1: 7 说明 最长异或序

简单的字典树(前缀树)

写这个树,主要是为了完成这道题目.http://hihocoder.com/problemset/problem/1014 代码如下,注释有比较详细的解释 1 #include <iostream> 2 #include <string> 3 #include <typeinfo> 4 #include <vector> 5 using namespace std; 6 7 /*****************************************

Luogu Dynamic Ranking (带修改的主席树)

带修改的主席树: 原本的主席树是维护了一个线段树前缀. 那么前缀有没有想到什么东西? 树状数组\(Bits\)是不是很 ...... ? 那么现在,我们用树状数组套主席树,不就可以实现带修改的可持久化了吗. 具体来说 \(T[1]维护rt[1]\) , \(T[2]维护rt[1].rt[2]\) , \(T[3]维护rt[3]\) ...... 就与树状数组是一样的. 那么现在,两个具体的操作: 修改: 修改需要修改\(logN\)棵主席树,将涉及修改节点的\(log\)个主席树先删后加点即可.

【数据结构】字典树/Trie树/前缀树 - 字符串的统计、排序和保存

字典树 描述 字典树,又称单词查找树.Trie树.前缀树,是一种树形结构,是一种哈希树的变种. 典型应用是用于统计.排序和保存大量的字符串(但不仅限于字符串). 常见操作有插入和查找,删除操作少见. 性质 根节点不包含字符 除根节点外每一个节点都只包含一个字符 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串 每个节点的所有子节点包含的字符都不相同 优点 利用字符串的公共前缀来减少查询时间 最大限度地减少无谓的字符串比较 查询效率比哈希树高 自带字典序排序 直接判断重复,或者记