思路:
一时卡了忘记字典树了, 写了一大片的
splay
s
p
l
a
y
,还调试了老久,
splay
s
p
l
a
y
直接加个懒惰标记就行了, 就是和线段树一样,对于前缀为
si
s
i
的变化和查询,我们可以找出这个前缀所在的位置区间
[l,r]
[
l
,
r
]
,这样将一棵树分成三棵树
[1,l−1],[l,r],[r+1,n]
[
1
,
l
−
1
]
,
[
l
,
r
]
,
[
r
+
1
,
n
]
,那么查询和更新的就是中间那棵树,之后再合并下就行了。为了保证一定可以分成三棵树, 可以在初始状态加两个不影响答案的名字。
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e5 + 10;
const int maxnode = 1e5 + 10;
const ll mod = 1e9 + 7;
using namespace std;
struct Splay {
int root, treapcnt;
string key[maxnode];
int pr[maxnode];
ll val[maxnode], va[maxnode], sum[maxnode];;
int ch[maxnode][2], cnt[maxnode], sz[maxnode];
void init() {
root = 0; treapcnt = 1;
sz[0] = 0; val[0] = 0;
sum[0] = 0; va[0] = 0;
memset(ch[0], 0, sizeof ch[0]);
}
void update(int x) {
sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + cnt[x];
val[x] = val[ch[x][0]] + val[ch[x][1]] + va[x];
}
void push_down(int x) {
if(!x) return ;
int ls = ch[x][0], rs = ch[x][1];
if(ls) { sum[ls] += sum[x]; val[ls] += sum[x] * sz[ls]; }
if(rs) { sum[rs] += sum[x]; val[rs] += sum[x] * sz[rs]; }
va[x] += sum[x] * cnt[x]; sum[x] = 0;
update(x);
}
void _rotate(int &x, int t) {
int y = ch[x][t ^ 1];
push_down(x); push_down(y);
ch[x][t ^ 1] = ch[y][t];
ch[y][t] = x;
update(x); update(y);
x = y;
}
void __insert(int &x, string new_name, int _val) {
push_down(x);
if(x) {
if(key[x] == new_name) { cnt[x]++; val[x] += _val; va[x] += _val; }
else {
int t = key[x] < new_name;
__insert(ch[x][t], new_name, _val);
if(pr[ch[x][t]] < pr[x]) _rotate(x, t ^ 1);
}
} else {
x = treapcnt++;
key[x] = new_name;
cnt[x] = 1;
val[x] = _val;
va[x] = _val;
sum[x] = 0;
pr[x] = rand();
ch[x][0] = ch[x][1] = 0;
}
update(x);
}
void splay(int &x, int k) {
push_down(x);
int cmp, d, siz = sz[ch[x][0]];
if(k <= siz) cmp = 0;
else {
k -= siz + cnt[x];
if(k <= 0) cmp = -1;
else cmp = 1;
}
if(cmp != -1) {
int &son = ch[x][cmp];
int siz2 = sz[ch[son][0]];
push_down(son);
if(k <= siz2) d = 0;
else {
k -= siz2 + cnt[son];
if(k <= 0) d = -1;
else d = 1;
}
if(d != -1) {
splay(ch[son][d], k);
if(d == cmp) _rotate(x, cmp ^ 1);
else _rotate(son, cmp);
}
_rotate(x, cmp ^ 1);
}
}
int Merge(int &l, int &r) {
splay(l, sz[l]);
ch[l][1] = r;
update(l);
return l;
}
void split(int &o, int k, int &l, int &r) {
splay(o, k);
l = o; r = ch[o][1];
ch[o][1] = 0;
update(l);
}
ll query1(int x, string name) {
push_down(x);
if(key[x] == name) return va[x];
if(!x) return 0;
if(name < key[x]) return query1(ch[x][0], name);
else return query1(ch[x][1], name);
}
int low_sz(int x, string name) {
if(!x) return 1;
push_down(x);
if(name == key[x]) return sz[ch[x][0]] + 1;
if(name < key[x]) return low_sz(ch[x][0], name);
else return sz[ch[x][0]] + cnt[x] + low_sz(ch[x][1], name);
}
ll solve(string name, ll flag) {
int len = name.length() - 1;
int sz1 = low_sz(root, name);
name[len]++;
int sz2 = low_sz(root, name);
if(sz2 == sz1) return 0;
int lroot, mid, mi_r, rroot;
split(root, sz1 - 1, lroot, mid);
split(mid, sz2 - sz1, mi_r, rroot);
if(flag != maxn) { sum[mi_r] += flag; val[mi_r] += flag * sz[mi_r]; } //变化fla
splay(mi_r, 1); ll ans = val[mi_r];
root = Merge(mi_r, rroot);
root = Merge(lroot, root);
return ans;
}
} sp;
string min_inf, max_inf;
char inf[maxn];
int main() {
inf[1] = 0; inf[0] = 1; min_inf = inf;
inf[0] = 255; min_inf = inf;
int q;
while(scanf("%d", &q) != EOF) {
sp.init();
sp.__insert(sp.root, min_inf, 0);
sp.__insert(sp.root, max_inf, 0);
while(q--) {
int op, val;
string name;
scanf("%d", &op); cin >> name;
if(op == 1) {
scanf("%d", &val);
sp.__insert(sp.root, name, val);
} else if(op == 2) {
scanf("%d", &val);
sp.solve(name, val);
} else if(op == 3) {
ll ans = sp.query1(sp.root, name);
printf("%lld\n", ans);
} else {
ll ans = sp.solve(name, maxn);
printf("%lld\n", ans);
}
}
}
return 0;
}