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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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还需要完善两道题还缺少互相的代码