You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

118 lines
3.5 KiB

2 years ago
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int N = 33000, INF = 0x3f3f3f3f;
struct Node {
int l, r; //左右儿子的节点号
int key; // BST中的真实值
int val; //堆中随机值,用于防止链条化
int size; //小于等于 key的数字个数用于计算rank等属性
} tr[N];
int root, idx; //用于动态开点配合tr记录FHQ Treap使用
int x, y, z; //本题用的三个临时顶点号
void pushup(int p) {
tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1; //合并信息
}
int get_node(int key) { //创建一个新节点
tr[++idx].key = key; //创建一个新点值为key
tr[idx].val = rand(); //随机一个堆中索引号
tr[idx].size = 1; //新点所以小于等于它的个数为1个只有自己
return idx; //返回点号
}
//将以p为根的平衡树进行分裂小于等于key的都放到以x为根的子树中大于key放到以y为根的子树中
void split(int p, int key, int &x, int &y) {
if (!p) { //当前节点为空
x = y = 0;
return;
}
if (tr[p].key <= key)
x = p, split(tr[p].r, key, tr[p].r, y); // x确定了左边确定了但右边未确定需要继续递归探索
else
y = p, split(tr[p].l, key, x, tr[p].l); // y确定了右边确定了但左边未确定需要继续递归探索
pushup(p); //更新统计信息
}
//将以xy为根的两个子树合并成一棵树.要求x子树中所有key必须小于等于y子树中所有key
int merge(int x, int y) {
if (!x || !y) return x + y; //如果x或者y有一个是空了那么返回另一个即可
int p; //根,返回值
if (tr[x].val > tr[y].val) { // x.key<y.key,并且, tr[x].val > tr[y].val, x在y的左上此时理解为大根堆,y向x的右下角合并
p = x;
tr[x].r = merge(tr[x].r, y);
} else {
p = y;
tr[y].l = merge(x, tr[y].l); //复读机
}
pushup(p); //更新统计信息
return p;
}
void insert(int key) {
split(root, key, x, y); //按k分割
root = merge(merge(x, get_node(key)), y); //在x与key节点合并,再与key合并
}
//返回key的前驱可以和key值一样,此处与上一题不同上一题要求强制比key小
int get_prev(int key) {
split(root, key, x, y); //按key分,x最右节点就是前驱
int p = x;
while (tr[p].r) p = tr[p].r; //向右走
int res = tr[p].key;
root = merge(x, y);
return res;
}
//返回key的后继
int get_next(int key) {
split(root, key, x, y); //按key分y最左节点是后继
int p = y;
while (tr[p].l) p = tr[p].l;
int res = tr[p].key;
root = merge(x, y);
return res;
}
//创建FHQ Treap带哨兵的空树
void build() {
get_node(-INF), get_node(INF);
root = 1, tr[1].r = 2; //+inf > -inf,+inf在-inf右边
pushup(root); //更新root的size
}
int main() {
//加快读入
ios::sync_with_stdio(false), cin.tie(0);
//事实证明,套路很重要
build();
int n;
cin >> n;
int res = 0;
int x;
for (int i = 1; i <= n; i++) {
cin >> x;
if (i == 1)
res += x;
else
res += min(abs(x - get_prev(x)), abs(get_next(x) - x));
insert(x);
}
printf("%d\n",res);
return 0;
}
// set ,vector还需要完善两道题还缺少互相的代码