洛谷:P2234 [HNOI2002]营业额统计

原题地址:https://www.luogu.org/problemnew/show/P2234

题目简述

给定一个序列,对于每一个数都要查询:序列中在这个数前与这个数最接近的数是什么?然后将最接近的数字与这个数字的差累加。(序列第一个数字直接加自己)

思路

查询在这个数之前与这个数最接近的数,我们很容易想到用二叉搜索树(BST)来做。
虽然数据略水暴力排序每次查询从一个数往左右找也能过。
每次插入一个数字,然后查询,我用Treap实现(还是弱化版的,只有插入查询)。
Treap的核心其实就是打乱顺序插入防止被卡(粗糙理解)。具体实现方法不难,请百度。(我之后会写一篇专门介绍下各种BST的。)
PS:Treap树完整版之后写。这题用STL的vector也行,vector理论每次插入渐进时间复杂度是O(n)但是听说实际是对数级别的?

代码

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
inline int randad(){
    static int seed=114; //seed可以随便取
    return seed=int(seed*48271LL%2147483647);//48271使得其有完全周期,即2147483647内取遍不重复 
}
struct Treap {
    int key,pri,son[2];
}T[33333];
int cnt=1,rt=0;
void rotate(int p,int &rt)
{
    int y=T[rt].son[p];
    T[rt].son[p]=T[y].son[!p];
    T[y].son[!p]=rt;
    rt=y;
}
void ins(int key,int &rt)
{
    if(rt==0)
    	T[rt=cnt++] = (Treap){key,randad()};
    else
    {
        int p=key>T[rt].key;
        ins(key,T[rt].son[p]);
        if(T[T[rt].son[p]].pri>T[rt].pri)
        	rotate(p,rt);   
    }
}
int nowMin(int key,int rt)//查询现在最接近key的数
{
    if(rt==0) return 666666666;
    int res=abs(key-T[rt].key);
    if(key>T[rt].key) res=min(res,nowMin(key,T[rt].son[1]));
    else if(key<T[rt].key) res=min(res,nowMin(key,T[rt].son[0]));
    return res;
}
int n,tot=0;
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) {
        int num;
        scanf("%d",&num);
        if (i==1) tot+=num;
        else tot+=nowMin(num,rt);//rt是当前根
        ins(num,rt);
    }
    printf("%d",tot);
    return 0;
} 
posted @ 2018-02-27 23:58  yyy2015c01  阅读(206)  评论(0编辑  收藏  举报

在寒风中颤抖之时、听到了歌声—— 在傍晚的校园里,在无人在的食堂里,在孤寂的校舍窗边。
三年前被冰封的那首歌曲。 被热情突然迫动,点缀着纯粹的思念,欺瞒的歌曲逐渐溶化在夜里。
那时,三人一起的冬天已经远去, 一个人和另一个人的季节却在循环往复。 后续,就在这样的晚秋。 那个时候似要撕裂的羁绊的丑陋伤痕尚未干却, 但是伴随着有什么将要改变的预感中,开始了。
寂寞的两首旋律,互相吸引而再伤害彼此, 因此,新的旋律被召集来了。
不久,新的冬天即将到来。 不能和那个人在一起、而另一个人也已不在的冬天。
“白色相簿”什么的,已经无所谓了。 因为已经不再有歌,值得去唱了。
传达不了的恋情,已经不需要了。 因为已经不再有人,值得去爱了。