欲望以提升热忱,毅力以磨平高山!|

XichenOC

园龄:1个月粉丝:4关注:0

2025-01-21 19:37阅读: 8评论: 0推荐: 0

P2234 [HNOI2002] 营业额统计

P2234 [HNOI2002] 营业额统计

题目翻译:

给定 \(n\) 个数,每一个数都要统计其最小波动值,波动值的定义是当天银收额和之前某次的营收额的差的绝对值,而要求每一天最小波动值的和(第一天波动值为当天营收额)

思路:

分析题目可以发现,最小波动值就是当天营收额与之前小于它的最大营收额的差的绝对值或之前大于它的最小营收额的差的绝对值。即当天的营收额的前驱和后继。想到这里就会想到二叉搜索树,为了防止树太高被卡,于是用平衡树来维护,接下来就是直接套模板即可。

注意: 要提前在树中插入一个极大值和极小值。

完整代码:

#include<bits/stdc++.h>
#define lc(x) tr[(x)].s[0]
#define rc(x) tr[(x)].s[1]
#define fa(x) tr[(x)].fa
using namespace std;
const int N=32800;
const int INF=0x3f3f3f3f;
struct tree{
    int s[2],key,fa,siz;
    tree(){s[0]=s[1]=fa=key=siz=0;}
}tr[N];
int rt,cnt;
void clear(int x){
    lc(x)=rc(x)=fa(x)=tr[x].key=tr[x].siz=0;
}
void pushup(int x){
    tr[x].siz=tr[lc(x)].siz+tr[rc(x)].siz;
}
bool get(int x){
    return x==rc(fa(x));
}
int newnode(int key){
    tr[++cnt].key=key;
    tr[cnt].siz=1;
    return cnt;
}
void rotate(int x){
    int y=fa(x),z=fa(y),c=get(x);
    if(tr[x].s[c^1]){
        fa(tr[x].s[c^1])=y;
    }
    tr[y].s[c]=tr[x].s[c^1];
    tr[x].s[c^1]=y;
    fa(y)=x;
    fa(x)=z;
    if(z)tr[z].s[y==tr[z].s[1]]=x;
    pushup(y);
    pushup(x);
}
void splay(int x){
    for(int f=fa(x);f=fa(x),f;rotate(x)){
        if(fa(f))rotate(get(x)==get(f)?f:x);
    }
    rt=x;
}
void ins(int key){
    int now=rt,f=0;
    while(now){
        f=now;
        now=tr[now].s[key>tr[now].key];
    }
    now=newnode(key);
    fa(now)=f;
    tr[f].s[key>tr[f].key]=now;
    splay(now);
}
int pre(int key){
    int now=rt,f=0,ans=0;
    while(now){
        f=now;
        if(tr[now].key>=key){
            now=lc(now);
        }
        else{
            ans=tr[now].key;
            now=rc(now);
        }
    }
    splay(f);
    return ans;
}
int nxt(int key){
    int now=rt,f=0,ans=0;
    while(now){
        f=now;
        if(tr[now].key<=key){
            now=rc(now);
        }
        else{
            ans=tr[now].key;
            now=lc(now);
        }
    }
    splay(f);
    return ans;
}
map<int,bool>vis;
signed main(){
    long long n,ans=0;
    scanf("%lld",&n);
    ins(INF),ins(-INF);
    int val;
    scanf("%d",&val);
    ins(val);
    ans+=val;
    vis[val]=true;
    for(int i=2;i<=n;i++){
        int val;
        scanf("%d",&val);
        if(vis[val]){
            continue;
        }
        vis[val]=true;
        ins(val);
        ans+=min(abs(val-pre(val)),abs(val-nxt(val)));
    }
    printf("%lld\n",ans);
}

平衡树讲解

本文作者:XichenOC

本文链接:https://www.cnblogs.com/XichenOC/p/18684326

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   XichenOC  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起