[bzoj1588][HNOI2002]营业额统计

本文介绍了一种算法,用于解决给定一组数后,计算每个数与其前面所有数差值绝对值的最小值之和的问题。算法采用离散化处理结合权值线段树二分查找、Splay树以及双向链表等多种数据结构实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给出n个数,求每个数和它前面每个数的差值绝对值的最小值之和。
n<=32767

Solution

很显然求前驱后驱。
可以离散化后用权值线段树二分找。
也可以直接用splay找。
或者还可以离线排完序用双向链表找。
你喜欢就好喽。。。

Orz bzoj上rank1 0ms踩所有人

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 50005
using namespace std;
const int inf=0x7fffffff;
int n,x,a,b,ans,tot,root,t[N][2],f[N],key[N];
void insert(int &v,int y,int fa) {
    if (!v) {v=++tot;key[v]=y;f[v]=fa;return;}
    if (key[v]>y) insert(t[v][0],y,v);
    else insert(t[v][1],y,v);
}
int son(int x) {return t[f[x]][1]==x;}
void rotate(int x) {
    int y=f[x],z=son(x);f[x]=f[y];
    if (f[x]) t[f[x]][son(y)]=x;
    if (t[x][1-z]) f[t[x][1-z]]=y;
    f[y]=x;t[y][z]=t[x][1-z];t[x][1-z]=y;
}
void splay(int x,int y) {
    while (f[x]!=y) {
        if (f[f[x]]!=y)
            if (son(x)==son(f[x])) rotate(f[x]);
            else rotate(x);
        rotate(x);
    }
    if (!y) root=x;
}
int pre(int x) {
    x=t[x][0];
    while (x) {
        if (t[x][1]) x=t[x][1];
        else break;
    }
    return x;
}
int suf(int x) {
    x=t[x][1];
    while (x) {
        if (t[x][0]) x=t[x][0];
        else break;
    }
    return x;
}
int main() {
    scanf("%d",&n);
    scanf("%d",&x);
    insert(root,x,0);ans=x;
    fo(i,2,n) {
        scanf("%d",&x);
        insert(root,x,0);splay(tot,0);
        int l=pre(root);if (l) a=x-key[l];else a=inf;
        int r=suf(root);if (r) b=key[r]-x;else b=inf;
        ans+=min(a,b);
    }
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值