[Wannafly挑戰賽14 B 前綴查詢]字典樹

[Wannafly挑戰賽14 B 前綴查詢]字典樹

分類:Data Structure Trie Tree Prefix Tree

1. 題目鏈接

[Wannafly挑戰賽14 B 前綴查詢]

2. 題意描述

在一個 Minecraft 村莊中,村長有這一本小寫字母構成的名冊(字符串的表),
每個名字旁邊都記錄着這位村民的聲望值,而且有的村民還和別人同名。
隨着時間的推移,因爲沒有村民死亡,這個名冊變得十分大。
現在需要您來幫忙維護這個名冊,支持下列 4 種操作:

1. 插入新人名 si,聲望爲 ai
2. 給定名字前綴 pi 的所有人的聲望值變化 di
3. 查詢名字爲 sj 村民們的聲望值的和(因爲會有重名的)
4. 查詢名字前綴爲 pj 的聲望值的和

輸入描述:
第一行爲兩個整數 0N105 ,表示接下來有 N 個操作;
接下來 N 行,每行輸入一個操作,行首爲一個整數 1oi4 ,表示這一行的操作的種類,
那麼這一行的操作和格式爲:

1. 插入人名,這一行的格式爲 1 si ai,其中 |ai| ≤ 10^3
2. 前綴修改聲望,這一行的格式爲 2 pi di,其中 |di| ≤ 10^3
3. 查詢名字的聲望和,這一行的格式爲 3 sj
4. 查詢前綴的聲望和,這一行的格式爲 4 pj

輸入保證插入人名的字符串的長度和小於或等於 105 ,總的字符串的長度和小於或等於 106
輸出描述:
對於每一次詢問操作,在一行裏面輸出答案。

輸入

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

3. 解題思路

維護前綴???字典樹。。。
本題需要進行單點插入、子樹(前綴)更新、單點查詢、子樹(前綴)查詢。
對於子樹更新操作,需要維護一個懶惰標記。
考慮好細節。
感覺現在腦殘加手殘的我,寫的代碼總是有一堆Bug

4. 實現代碼

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;

const int inf = 0x3f3f3f3f;
const long long infl = 0x3f3f3f3f3f3f3f3fLL;

template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }

const int MAXL = 100010;

int n;

struct TNode {
    long long sum;
    long long val;
    long long tag;
    int cnt;
    int same;
    int ch[27];
} node[MAXL];
int tot, root;
void init() {
    tot = 0;
    root = ++ tot;
    memset(node, 0, sizeof(node));
}

inline void pushDown(int pos) {
    if (!pos || node[pos].tag == 0) return;
    for (int j = 0; j < 26; ++j) {
        if (node[pos].ch[j] == 0) continue;
        node[node[pos].ch[j]].tag += node[pos].tag;
        node[node[pos].ch[j]].sum += node[node[pos].ch[j]].cnt * node[pos].tag;
        node[node[pos].ch[j]].val += node[node[pos].ch[j]].same * node[pos].tag;
    }
    node[pos].tag = 0;
}

void insert(char name[], long long val) {
    int pos = root;
    for (int i = 0; name[i]; ++i) {
        pushDown(pos);
        int dig = name[i] - 'a';
        if (node[pos].ch[dig] == 0) node[pos].ch[dig] = ++ tot;
        node[pos].sum += val;
        node[pos].cnt += 1;
        pos = node[pos].ch[dig];
    }
    pushDown(pos);
    node[pos].sum += val;
    node[pos].val += val;
    node[pos].cnt += 1;
    node[pos].same += 1;
}

void update(char name[], long long val) {
    int pos = root;
    for (int i = 0; name[i]; ++i) {
        int dig = name[i] - 'a';
        if (node[pos].ch[dig] == 0) return;
        pos = node[pos].ch[dig];
    }
    long long cnt = node[pos].cnt;

    pos = root;
    for (int i = 0; name[i]; ++i) {
        pushDown(pos);
        int dig = name[i] - 'a';
        if (node[pos].ch[dig] == 0) return;
        node[pos].sum += cnt * val;
        pos = node[pos].ch[dig];
    }
    pushDown(pos);
    node[pos].sum += node[pos].cnt * val;
    node[pos].val += node[pos].same * val;
    node[pos].tag += val;
}

long long query_prefix(char name[]) {
    int pos = root;
    for (int i = 0; name[i]; ++i) {
        pushDown(pos);
        int dig = name[i] - 'a';
        if (node[pos].ch[dig] == 0) return 0;
        pos = node[pos].ch[dig];
    }
    pushDown(pos);
    return node[pos].sum;
}

long long query_name(char name[]) {
    int pos = root;
    for (int i = 0; name[i]; ++i) {
        pushDown(pos);
        int dig = name[i] - 'a';
        if (node[pos].ch[dig] == 0) return 0;
        pos = node[pos].ch[dig];
    }
    pushDown(pos);
    return node[pos].val;
}

void print(int pos, string path) {
    debug(path, node[pos].sum, node[pos].val, node[pos].cnt, node[pos].same);
    for (int j = 0; j < 26; ++j) {
        pushDown(pos);
        if (node[pos].ch[j] == 0) continue;
        char ch = j + 'a';
        print(node[pos].ch[j], path + ch);
    }
}

char name[MAXL];

int main() {
#ifdef ___LOCAL_WONZY___
    freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    while (~scanf("%d", &n)) {
        int oper, val;
        init();
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &oper);
            if (oper == 1) {
                scanf("%s %d", name, &val);
                insert(name, val);
                // print(root, "");
            } else if (oper == 2) {
                scanf("%s %d", name, &val);
                update(name, val);
                // print(root, "");
            } else if (oper == 3) {
                scanf("%s", name);
                long long ans = query_name(name);
                printf("%lld\n", ans);
            } else {
                scanf("%s", name);
                long long ans = query_prefix(name);
                printf("%lld\n", ans);
            }
        }

    }
#ifdef ___LOCAL_WONZY___
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章