• BZOJ 1588 [HNOI2002]营业额统计(双向链表)


     

    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1588

     

    【题目大意】

      给出一个数列,对于每个数,选择其前面的某个数作差取绝对值,
      使得所有差的绝对值的和最小,第一个数统计其值作为该数的答案。

     

    【题解】

      题目等价于在一个数前面寻找最接近的一个数,
      显然这是一个平衡树求前继和后继能解决的为问题,
      然而因为题目可以离线,我们考虑编码复杂度更低的基础数据结构,
      我们将所有数据排序,构造双向链表,那么单节点左右就是与其差值最小的数,
      我们按数列逆序处理节点,当计算完一个节点之后将其从链表中删除即可。
      由于链表的有序性,使得剩余节点始终满足左右节点为当前剩余点中与该节点差值最小的点,
      复杂度O(nlogn).

     

    【代码】

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=500000;
    struct data{int l,r,num,id;}p[N];
    bool cmp(data a,data b){return a.num<b.num;}
    int n,pos[N];
    int main(){
        while(~scanf("%d",&n)){
            for(int i=1;i<=n;i++)scanf("%d",&p[i].num),p[i].id=i;
            sort(p+1,p+n+1,cmp);
            for(int i=1;i<=n;i++){
                p[i].l=i-1,p[i].r=i+1;
                pos[p[i].id]=i;
            }p[n].r=0;
            long long ans=p[pos[1]].num;
            for(int i=n;i>1;i--){
                int x=pos[i];
                if(p[x].l&&p[x].r){
                    ans+=min(p[p[x].r].num-p[x].num,p[x].num-p[p[x].l].num);
                    p[p[x].l].r=p[x].r;
                    p[p[x].r].l=p[x].l;
                }else if(p[x].l){
                    ans+=p[x].num-p[p[x].l].num;
                    p[p[x].l].r=0;
                }else{
                    ans+=p[p[x].r].num-p[x].num;
                    p[p[x].r].l=0;
                }
            }printf("%lld
    ",ans);
        }return 0;
    }
  • 相关阅读:
    遍历数组的常用方法
    ios 提审被拒4.3,更换账号提审处理
    js 判断手机有没有网络
    js网页拉起支付宝支付
    uni-app常用 HTML5+APP 设置
    uni-app 无痛刷新 token 方法
    uni-app通过判断接口403跳转登录页面的问题
    APICloud项目纪要
    Vue递归组件实现层层嵌套显示数据
    Git恢复删除的分支
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj1588.html
Copyright © 2020-2023  润新知