题意:
给出N天的营业额,定义某天营业额的“最小波动值”为这天之前所有营业额与该天营业额之差的绝对值的最小值。特别地,第一天营业额的“最小波动值”即为第一天营业额本身。
实质:给定一个序列
{ai}
,求:
a1+∑2⩽i⩽nminj<i{∣∣ai−aj∣∣}
解法:
如果顺序记下每天的营业额并使之有序的话,我们会发现,每加入一天的营业额,它的前驱和后继与它差值之中小的一个即为这一天的“最小波动值”,累加答案即可。
因此我们可以用BST维护营业额,每插入一个数就查询前驱和后继。但是在实践中有一种编程复杂度更低,而效果很好的方法:用插入时走过的路径上的所有点维护答案即可,正确性显然。
(不要随便看代码。不要随便看代码。不要随便看代码。因为很重要所以说三次。)
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <ctime>
using namespace std;
//Global Variables & Definitions
int N;
inline int iabs(int a) {
return a > 0 ? a : -a;
}
//End Global Variables & Definitions
//Treap
struct node {
node *ch[2];
int v;
int r;
node() : r(rand()) { ch[0] = ch[1] = NULL; }
node(int v) : v(v), r(rand()) { ch[0] = ch[1] = NULL; }
int cmp(int va) {
return va < this -> v ? 0 : 1;
}
};
void Rotate(node* & o, int d) {
node *k = o -> ch[d ^ 1];
o -> ch[d ^ 1] = k -> ch[d];
k -> ch[d] = o;
o = k;
}
int Insert(node* & o, int v) {
int t = iabs(v - o -> v), t2 = 0x7fffffff;
int d = o -> cmp(v);
if(o -> ch[d] == NULL) {
o -> ch[d] = new node(v);
} else {
t2 = Insert(o -> ch[d], v);
}
if(o -> r < o -> ch[d] -> r) Rotate(o, d ^ 1);
return min(t, t2);
}
//End Treap
//Main Structure
node *root;
inline void ir() {
//srand(time(NULL));
srand(20150423);
scanf("%d", &N);
}
int main() {
ir();
int ans = 0, temp;
//1st
if(!~scanf("%d", &temp)) temp = 0;
ans = temp;
root = new node(temp);
//else
for(int i = 1;i < N;++i) {
if(!~scanf("%d", &temp)) temp = 0;
ans += Insert(root, temp);
}
printf("%d\n", ans);
return 0;
}
在BZOJ上srand(time(NULL))奇怪的RE了,所以随便指定了一个种子。
傲娇的BZOJ又抽风