法1 Splay
每次insert之后,当前点已经旋到根,找到前驱后继,减一减计较,较小的那个统计到ans里
码量太长弱点~~
Code:
#include <bits/stdc++.h>
#define maxn 100010
#define LL long long
using namespace std;
int rt, sz, f[maxn], val[maxn], size[maxn], son[maxn][2];
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){
++sz;
val[sz] = x, size[sz] = 1, f[sz] = 0, son[sz][0] = son[sz][1] = 0;
return sz;
}
void pushup(int x){ size[x] = size[son[x][0]] + size[son[x][1]] + 1; }
int get(int x){ return son[f[x]][1] == x; }
void connect(int x, int y, int z){
f[x] = y, son[y][z] = x;
}
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);
pushup(fa); pushup(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 fa = 0, now = rt;
while (1){
if (!now){
now = addnode(x);
if (fa) connect(now, fa, x > val[fa]);
pushup(fa); splay(now, 0);
return;
}
fa = now, now = son[now][x > val[now]];
}
}
int kth(int now, int k){
if (!now) return 0;
while (1){
if (size[son[now][0]] >= k) now = son[now][0]; else
if (size[son[now][0]] + 1 >= k) return now; else
k -= size[son[now][0]] + 1, now = son[now][1];
}
}
int main(){
int M = read(), x = read();
LL ans = x;
--M, rt = addnode(x), val[0] = 2e9;
while (M--){
int a = read();
insert(a);
int sum1 = abs(a - val[kth(son[rt][0], size[son[rt][0]])]), sum2 = abs(a - val[kth(son[rt][1], 1)]);
ans += min(sum1, sum2);
}
printf("%lld\n", ans);
return 0;
}
法2 fhq Treap
每读入一个数a,先
s
p
l
i
t
(
r
t
,
a
−
1
,
x
,
y
)
split(rt,a-1,x,y)
split(rt,a−1,x,y),找到前驱后继,即
k
t
h
(
x
,
s
i
z
e
[
x
]
)
,
k
t
h
(
y
,
1
)
kth(x,size[x]),kth(y,1)
kth(x,size[x]),kth(y,1)
然后向上面一样比较一下,最后insert
空树请注意一下,为了不让kth死循环,若now=0,返回0,并且一开始把
v
a
l
[
0
]
=
i
n
f
val[0]=inf
val[0]=inf,这样就不会干扰
Code:
#include <bits/stdc++.h>
#define maxn 100010
#define LL long long
using namespace std;
int rt, sz, val[maxn], key[maxn], size[maxn], son[maxn][2];
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){
++sz;
val[sz] = x, key[sz] = rand() * rand(), size[sz] = 1;
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 (val[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);
}
}
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;
}
}
int kth(int now, int k){
if (!now) return 0;
while (1){
if (size[son[now][0]] >= k) now = son[now][0]; else
if (size[son[now][0]] + 1 >= k) return now; else
k -= size[son[now][0]] + 1, now = son[now][1];
}
}
int main(){
srand(time(0));
int M = read(), x = read();
--M;
LL ans = x;
rt = addnode(x), val[0] = 2e9;
while (M--){
int a = read(), x, y;
split(rt, a - 1, x, y);
int sum1 = abs(a - val[kth(x, size[x])]), sum2 = abs(a - val[kth(y, 1)]);
ans += min(sum1, sum2);
rt = merge(merge(x, addnode(a)), y);
}
printf("%lld\n", ans);
return 0;
}