帶前綴修改的字典樹
阿新 • • 發佈:2018-04-24
重名 \n for return fin question bcb otto == 在一個 Minecraft 村莊中,村長有這一本小寫字母構成的名冊(字符串的表),
每個名字旁邊都記錄著這位村民的聲望值,而且有的村民還和別人同名。
隨著時間的推移,因為沒有村民死亡,這個名冊變得十分大。
現在需要您來幫忙維護這個名冊,支持下列 4 種操作: 1. 插入新人名 si,聲望為 ai
2. 給定名字前綴 pi 的所有人的聲望值變化 di
3. 查詢名字為 sj 村民們的聲望值的和(因為會有重名的)
4. 查詢名字前綴為 pj 的聲望值的和
2. 前綴修改聲望,這一行的格式為 2 pi di,其中 |di| ≤ 103
3. 查詢名字的聲望和,這一行的格式為 3 sj
4. 查詢前綴的聲望和,這一行的格式為 4 pj 輸入保證插入人名的字符串的長度和小於或等於 105,總的字符串的長度和小於或等於 106。
每個名字旁邊都記錄著這位村民的聲望值,而且有的村民還和別人同名。
隨著時間的推移,因為沒有村民死亡,這個名冊變得十分大。
現在需要您來幫忙維護這個名冊,支持下列 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; }
帶前綴修改的字典樹