#B. 「一本通 4.6 例 1」营业额统计

  • 传统题 1000ms 512MiB
  • 说明

    Tiger 最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger 拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。 经济管理学上定义了一种最小波动值来衡量这种情况:记该天以前某一天的营业额为 a_{i},该天营业额为 b,则该天的最小波动值 δ=min∣a_{i}​−b∣,当最小波动值越大时,就说明营业情况越不稳定。而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。 你的任务就是编写一个程序帮助 Tiger 来计算这一个值,第一天的最小波动值为第一天的营业额。

    一句话题意

    给出一个 n 个数的数列 {a_{n}​},对于第i 个元素a_{i}​,定义f_{i}​=min∣a_{i}​−a_{j}∣,其中 1≤j<i, ​f_{1}=​a_{1}。求 ∑f_{i}​。

    输入格式

    第一行为正整数,表示该公司从成立一直到现在的天数; 接下来的 n 行每行有一个整数,表示第i 天公司的营业额 a_{i}​。

    输出格式

    仅有一个正整数,即每一天最小波动的和,结果不超过 2^{31}

    样例

    输入数据 1

    6
    5
    1
    2
    5
    4
    6

    输出数据 1

    12

    提示


    数据范围:对于全部数据,1≤n<2^{15},∣a_{i}∣≤10^{6}
  • #include<bits/stdc++.h>
    using namespace std;
    struct S{
    	int lc,rc,vis,pos,cnt,sze;
    }t[500005];int n,m,cnt=0,rt=0;
    void zig(int &k){
    	int y=t[k].lc;
    	t[k].lc=t[y].rc;
    	t[y].rc=k;
    	t[y].sze=t[k].sze;
    	t[k].sze=t[t[k].lc].sze+t[t[k].rc].sze+t[k].cnt;
    	k=y;
    }
    void zag(int &k){
    	int y=t[k].rc;
    	t[k].rc=t[y].lc;
    	t[y].lc=k;
    	t[y].sze=t[k].sze;
    	t[k].sze=t[t[k].lc].sze+t[t[k].rc].sze+t[k].cnt;
    	k=y;
    }
    void inse(int &k,int key){
    	if(!k){
    		k=++cnt;t[k].vis=key;t[k].pos=rand();
    		t[k].cnt=t[k].sze=1;t[k].lc=t[k].rc=0;
    		return ;
    	}
    	else ++t[k].sze;
    	if(t[k].vis==key)++t[k].cnt;
    	else if(key<t[k].vis){
    		inse(t[k].lc,key);
    		if(t[t[k].lc].pos<t[k].pos)zig(k);
    	}
    	else {
    		inse(t[k].rc,key);
    		if(t[t[k].rc].pos<t[k].pos)zag(k);
    	}
    	return ;
    }
    void del(int &k,int key){
    	if(t[k].vis==key){
    		if(t[k].cnt>1)--t[k].cnt,--t[k].sze;
    		else if(!t[k].lc || !t[k].rc)k=t[k].lc+t[k].rc;
    		else if(t[t[k].lc].pos<t[t[k].rc].pos)zig(k),del(k,key);
    		else zag(k),del(k,key);
    		return ;
    	}
    	--t[k].sze;
    	if(key<t[k].vis)del(t[k].lc,key);
    	else del(t[k].rc,key);
    }
    int quepre(int key){
    	int k=rt,res=-0x3f3f3f3f;
    	while(k){
    		if(t[k].vis<key)res=t[k].vis,k=t[k].rc;
    		else k=t[k].lc;
    	}
    	return res;
    }
    int quenex(int key){
    	int k=rt,nex=0x3f3f3f3f;
    	while(k){
    		if(t[k].vis>=key)nex=t[k].vis,k=t[k].lc;
    		else k=t[k].rc;
    	}
    	return nex;
    }
    int main(){
    	int n;
    	int op,bn;
    	scanf("%d",&n);
    	scanf("%d",&op);
    	inse(rt,op);
    	bn=op;
    	for(int i=1;i<=n-1;i++)
    	{
    	    scanf("%d",&op);
    		int xx=quepre(op);
    		int yy=quenex(op);
    		int zz=min(op-xx,yy-op);
    		bn+=zz;inse(rt,op);
    	}
    	printf("%d",bn);
    	return 0;
    }

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值