洛谷2234 [HNOI2002]营业额统计 treap

题目

给出序列A
求a[1]+min(|a[i]-a[j]|)+…+min(|a[n]-a[j]|){1<=j<=i}
a[i]可能为负数

题解

听所用排序可以水过去
但是为了练习treap,我还是打了treap

就是找出和a[i]最接近的数,转化到treap中即求前驱和后继,然后在两数中选择与a[i]最小的差值计入答案
注意相同的数!!

代码

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>

using namespace std;

struct node{
    int l,r;
    int size,data,key;
}t[100000];
int n,root,cnt,ans;
const int m=100000000;

void updata(int x){
    t[x].size=t[t[x].l].size+t[t[x].r].size+1;
}

void rttn(int &x){
    int y=t[x].l;
    t[x].l=t[y].r;
    t[y].r=x;
    updata(x);updata(y);
    x=y;
}

void lttn(int &x){
    int y=t[x].r;
    t[x].r=t[y].l;
    t[y].l=x;
    updata(x);updata(y);
    x=y;
}

void insert(int &x,int k){
    if (x==0){
        x=++cnt;
        t[x].key=rand();
        t[x].data=k;
        t[x].size=1;
        return;
    }
    if (k<=t[x].data) {
        insert(t[x].l,k);
        if (t[x].key>t[t[x].l].key) rttn(x);
    } else {
        insert(t[x].r,k);
        if (t[x].key>t[t[x].r].key) lttn(x);
    }
    updata(x);
}

int pre(int k){
    int x=root,ans=-m;
    while (x){
        if (k==t[x].data) return t[x].data;
        if (k>t[x].data) ans=max(ans,t[x].data),x=t[x].r; 
                         else x=t[x].l;
    }
    return ans;
}

int next(int k){
    int x=root,ans=m;
    while (x){
        if (k==t[x].data) return t[x].data;
        if (k<t[x].data) ans=min(t[x].data,ans),x=t[x].l;
                         else x=t[x].r;
    }
    return ans;
}

int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        int x,pr,ne;
        scanf("%d",&x);
        pr=pre(x);
        ne=next(x);
        if (i==1) ans+=abs(x); else ans+=min(x-pr,ne-x);
        insert(root,x);
    }
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/yjy_aii/article/details/80884843