法1 Splay
可以用来练手splay
需要以下:
- i n s e r t ( x ) insert(x) insert(x):往下跑,若跑到空点,新开一个;若有重复,return
- M i n ( ) Min() Min():找到树中最便宜的点的编号,只要一直往左儿子跑就行了
- M a x ( ) Max() Max():找到树中最昂贵的点的编号,只要一直往右儿子跑就行了
- p r e ( ) pre() pre():找前驱
- d e l ( x ) del(x) del(x):删掉编号为x的点,不用findrank,用Min/Max就行了
Code:
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
int rt, sz, size[maxn], f[maxn], c[maxn], w[maxn], son[maxn][2];
int ansc, answ;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
void clear(int x){
f[x] = c[x] = w[x] = son[x][0] = son[x][1] = size[x] = 0;
}
int get(int x){ return son[f[x]][1] == x; }
void connect(int x, int y, int z){
if (x) f[x] = y;
if (y) son[y][z] = x;
}
void update(int x){
if (x){
size[x] = 1;
if (son[x][0]) size[x] += size[son[x][0]];
if (son[x][1]) size[x] += size[son[x][1]];
}
}
void rotate(int x){
int fa = f[x], ffa = f[fa], m = get(x), n = get(fa);
connect(son[x][m ^ 1], fa, m);
connect(fa, x, m ^ 1);
connect(x, ffa, n);
update(fa); update(x);
}
void splay(int x, int goal){
while (f[x] != goal){
int fa = f[x];
if (f[fa] != goal) rotate(get(x) == get(fa) ? fa : x);
rotate(x);
}
if (!goal) rt = x;
}
void insert(int x, int y){
int now = rt, fa = 0;
while (1){
if (!now){
now = ++sz;
c[now] = y, w[now] = x, size[now] = 1;
son[now][0] = son[now][1] = 0, f[now] = fa;
if (fa) son[fa][y > c[fa]] = now;
update(fa); splay(now, 0);
return;
}
if (c[now] == y) return;
fa = now, now = son[now][y > c[now]];
}
}
int Min(){
int x = rt;
while (son[x][0]) x = son[x][0];
return x;
}
int Max(){
int x = rt;
while (son[x][1]) x = son[x][1];
return x;
}
int pre(){
int x = son[rt][0];
while (son[x][1]) x = son[x][1];
return x;
}
void del(int x){
splay(x, 0);
if (!son[rt][0] && !son[rt][1]){
clear(rt);
rt = 0;
return;
}
if (!son[rt][0]){
int tmp = rt;
f[rt = son[rt][1]] = 0;
clear(tmp); return;
}
if (!son[rt][1]){
int tmp = rt;
f[rt = son[rt][0]] = 0;
clear(tmp); return;
}
int tmp = rt, left = pre();
splay(left, 0);
connect(son[tmp][1], rt, 1);
clear(tmp);
update(rt);
}
void sum(int x){
ansc += c[x], answ += w[x];
if (son[x][0]) sum(son[x][0]);
if (son[x][1]) sum(son[x][1]);
}
int main(){
int opt = read();
while (opt != -1){
if (opt == 1){
int x = read(), y = read();
insert(x, y);
} else
if (opt == 3){
int x = Min();
if (x) del(x);
} else{
int x = Max();
if (x) del(x);
}
opt = read();
}
sum(rt);
printf("%d %d\n", answ, ansc);
return 0;
}
法2 fhq Treap
这里用到两个按照w和size的split
非常好打,细节问题注意
Code:
#include <bits/stdc++.h>
#define maxn 100010
#define LL long long
using namespace std;
int sz, rt, beau[maxn], cost[maxn], size[maxn], key[maxn], son[maxn][2];
LL ans1, ans2;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int addnode(int x, int y){
++sz;
beau[sz] = x, cost[sz] = y, size[sz] = 1, key[sz] = rand() * rand();
return sz;
}
void pushup(int x){ size[x] = size[son[x][0]] + size[son[x][1]] + 1; }
void split(int now, int w, int &u, int &v){
if (!now) u = v = 0; else{
if (cost[now] <= w) u = now, split(son[now][1], w, son[u][1], v); else
v = now, split(son[now][0], w, u, son[v][0]);
pushup(now);
}
}
void split2(int now, int w, int &u, int &v){
if (!now) u = v = 0; else{
if (size[son[now][0]] >= w) v = now, split2(son[now][0], w, u, son[v][0]); else
u = now, split2(son[now][1], w - size[son[now][0]] - 1, son[u][1], v);
pushup(now);
}
}
int merge(int u, int v){
if (!u || !v) return u + v;
if (key[u] >= key[v]){
son[u][1] = merge(son[u][1], v);
pushup(u);
return u;
} else{
son[v][0] = merge(u, son[v][0]);
pushup(v);
return v;
}
}
void cnt(int now){
if (!now) return;
ans1 += beau[now], ans2 += cost[now];
cnt(son[now][0]); cnt(son[now][1]);
}
int main(){
srand(time(0));
int x, y, z;
int opt = read();
while (opt != -1){
if (opt == 1){
int xx = read(), yy = read();
split(rt, yy, x, y);
split(x, yy - 1, x, z);
if (size[z]) rt = merge(merge(x, z), y); else
rt = merge(merge(x, addnode(xx, yy)), y);
} else
if (size[rt])
if (opt == 2) split2(rt, size[rt] - 1, rt, x); else
split2(rt, 1, x, rt);
opt = read();
}
cnt(rt);
printf("%lld %lld\n", ans1, ans2);
return 0;
}