题意:
有一下4种操作:
- 插入新人名 x,声望为 v
- 给定名字前缀 x 的所有人的声望值变化 v (v为任意整数)
- 查询名字为 x 的人的声望值的和(会有重名的)
- 查询名字前缀为 x 的声望值的和
解析:
基本思路,建一棵树,每个结点代表一个字母,且往下有26路分支
eg:abae,abax,abad,abb,acc的存储形式如下
每个结点有两套值:
- now代表到当前位置为前缀的所有串的数量,pre代表到当前位置为前缀的所有串的声望的和
- en代表以当前段为名字的串的数量,pre代表以当前段为名字的串的声望的和
写代码的时候注意区分这两套值就可以了
代码:
#include<bits/stdc++.h>
using namespace std;
#define D long long
struct node{
node* next[27];
D now,pre,en,val,f;
//pre代表所有前缀为当前段的总和,val代表以当前段结尾的总和
//now代表所有前缀为当前段的数量,en代表以当前段结尾的数量
//数量的作用:在down懒惰标记的时候,加上 数量*标记
//abcd...在c位置标记,则以abc为前缀的所有本来都要加上标记的数
node(D now,D pre,D en,D val,D f):now(now),val(val),f(f),en(en),pre(pre){
for(int i=1;i<=26;i++)
next[i]=NULL;
}
void down(node *p){
if(p->f==0)return;
for(int i=1;i<=26;i++){
if(p->next[i]==NULL)continue;
p->next[i]->f+=p->f;
p->next[i]->pre+=(p->next[i]->now)*(p->f);
p->next[i]->val+=(p->next[i]->en)*(p->f);
}
p->f=0;
}
void insert(string x,D v){
node *p=this;
for(int i=0;i<x.length();i++){
int a=x[i]-'a'+1;
if(p->next[a]==NULL)p->next[a]=new node(1,v,0,0,0);
else p->next[a]->now++,p->next[a]->pre+=v;
p=p->next[a];
down(p);
}
p->en++,p->val+=v;
}
void add(string x,D v){
node *p=this;
for(int i=0;i<x.length();i++){
int a=x[i]-'a'+1;
if(p->next[a]==NULL)return;
p=p->next[a];
down(p);
}
D ti=p->now;
p=this;
for(int i=0;i<x.length();i++){
int a=x[i]-'a'+1;
p=p->next[a];
p->pre+=ti*v;
down(p);
}
p->val+=v*(p->en);
p->f+=v;
}
D finpre(string x){
node *p=this;
for(int i=0;i<x.length();i++){
int a=x[i]-'a'+1;
if(p->next[a]==NULL)return 0;
p=p->next[a];
down(p);
}
return p->pre;
}
D finname(string x){
node *p=this;
for(int i=0;i<x.length();i++){
int a=x[i]-'a'+1;
if(p->next[a]==NULL)return 0;
p=p->next[a];
down(p);
}
return p->val;
}
void print(){
node *p=this;
printf("now %lld, pre %lld, en %lld, val %lld, f %lld\n",p->now,p->pre,p->en,p->val,p->f);
}
}ro(0,0,0,0,0);
int main(){
int t;scanf("%d",&t);
while(t--){
int f;scanf("%d",&f);
if(f==1){
string x;D v;cin>>x;scanf("%lld",&v);
ro.insert(x,v);
}
else if(f==2){
string x;D v;cin>>x;scanf("%lld",&v);
ro.add(x,v);
}
else if(f==3){
string x;cin>>x;
printf("%lld\n",ro.finname(x));
}
else {
string x;cin>>x;
printf("%lld\n",ro.finpre(x));
}
}
}