[BZOJ1588][HNOI2002][Treap][Splay]營業額統計[水題]

題意:

    給出N天的營業額,定義某天營業額的“最小波動值”爲這天之前所有營業額與該天營業額之差的絕對值的最小值。特別地,第一天營業額的“最小波動值”即爲第一天營業額本身。
    實質:給定一個序列{ai} ,求:

a1+2inminj<i{aiaj}

解法:

    如果順序記下每天的營業額並使之有序的話,我們會發現,每加入一天的營業額,它的前驅和後繼與它差值之中小的一個即爲這一天的“最小波動值”,累加答案即可。
    因此我們可以用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又抽風

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章