1. 程式人生 > >帶前綴修改的字典樹

帶前綴修改的字典樹

重名 \n for return fin question bcb otto ==

在一個 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;
}

帶前綴修改的字典樹