HYSBZ 1588 营业额统计 (Splay)

题意:给出一个公司每一天的营业额,求每天的最小波动值之和。该天的最小波动值= min { 绝对值| 该天以前某一天的营业额-该天的营业额 | }。第一天的最小波动值就是其自己。

思路:Splay伸展树的入门题,仅有splay,insert,rotate这三个主要的函数而已。

  将一个数字(营业额)插入树中,并把其splay到根位置,然后其前驱和后继中离它较近的一个用来求最小波动值。注意可能没有前驱/后继。对第一个数特别处理。

  注意:此题的数据有缺陷,读入营业额之前先将变量清零。 

  1 #include <bits/stdc++.h>
  2 #define pii pair<int,int>
  3 #define INF 0x7f7f7f7f
  4 #define LL long long
  5 using namespace std;
  6 const int N=1000002;
  7 int root, node_cnt;
  8 struct node
  9 {
 10     int pre, val, ch[2];
 11 }nod[N];
 12
 13 int create_node(int v,int far)  //返回节点下标
 14 {
 15     nod[node_cnt].val=v;
 16     nod[node_cnt].pre=far;
 17     nod[node_cnt].ch[0]=0;
 18     nod[node_cnt].ch[1]=0;
 19     return node_cnt++;
 20 }
 21
 22 void Rotate(int t, int d)       //d为方向,0是左旋,1是右
 23 {
 24     int far=nod[t].pre;
 25     int son=nod[t].ch[d];       //far的孩子
 26     int gra=nod[far].pre;       //far的父亲
 27
 28     nod[son].pre=far;
 29     nod[t].pre=gra;
 30     nod[far].pre=t;
 31
 32     nod[far].ch[d^1]=son;
 33     nod[t].ch[d]=far;
 34     nod[gra].ch[nod[gra].ch[1]==far]=t;
 35 }
 36
 37 void Splay(int t,int goal)   //将t转为goal的任一孩子
 38 {
 39     while( nod[t].pre!=goal  )     //t还不是根
 40     {
 41         int f=nod[t].pre, g=nod[f].pre;
 42         if( g==goal )    Rotate( t, nod[f].ch[0]==t );    //父亲就是根s,旋1次
 43         else
 44         {
 45             int d1=(nod[f].ch[0]==t), d2=(nod[g].ch[0]==f);
 46             if( d1==d2 )    //两次同向旋转
 47             {
 48                 Rotate( f, d1);
 49                 Rotate( t, d1);
 50             }
 51             else            //两次反向旋转
 52             {
 53                 Rotate( t, d1);
 54                 Rotate( t, d2);
 55             }
 56         }
 57     }
 58     if(!goal)    root=t;        //时刻更新树根
 59 }
 60
 61 int Insert(int t, int v)
 62 {
 63     if(v==nod[t].val)   return -1;
 64     int q=-1;
 65     if( v>nod[t].val )  //右边
 66     {
 67         if( nod[t].ch[1]==0 )   q=(nod[t].ch[1]=create_node(v, t));
 68         else                    q=Insert(nod[t].ch[1], v);
 69     }
 70     else                //左边
 71     {
 72         if( nod[t].ch[0]==0 )  q=(nod[t].ch[0]=create_node(v, t));
 73         else                   q=Insert(nod[t].ch[0], v);
 74     }
 75     return q;
 76 }
 77 int get_pre(int t, int d)   //求前驱和后继的,d=1代表求前驱
 78 {
 79     if(nod[t].ch[d])    return get_pre(nod[t].ch[d], d);
 80     return nod[t].val;
 81 }
 82
 83 void init()
 84 {
 85     root=node_cnt=0;
 86     create_node(INF,0);       //0号点是不要的
 87 }
 88 int main()
 89 {
 90     freopen("input.txt", "r", stdin);
 91     int n;
 92     while(cin>>n)
 93     {
 94         init();
 95         int ans=0;
 96         for(int i=0,a=0; i<n; i++,a=0)
 97         {
 98             scanf("%d", &a);
 99             int t=Insert(root, a);
100             if(t<0)     continue;          //已经存在此数字
101             Splay(t, 0);                   //将t伸展一下到根
102             if(i==0)  ans=a;               //第一个数字
103             else if( nod[t].ch[0] && nod[t].ch[1] )
104                 ans+=min( abs(a-get_pre(nod[t].ch[0], 1)), abs(a-get_pre( nod[t].ch[1], 0)));
105             else if( nod[t].ch[0] )    ans+=abs( a-get_pre( nod[t].ch[0], 1) );
106             else if( nod[t].ch[1] )    ans+=abs( a-get_pre( nod[t].ch[1], 0) );
107
108         }
109         cout<<ans<<endl;
110     }
111     return 0;
112 }

AC代码

时间: 2024-09-30 00:41:49

HYSBZ 1588 营业额统计 (Splay)的相关文章

BZOJ 1588 营业额统计 Splay

主要操作为Splay中插入节点,查找前驱和后继节点. 1: #include <cstdio> 2: #include <iostream> 3: #include <cmath> 4: using namespace std; 5: #define MaxL 100005 6: #define INF 0x7ffffff 7: #define keyTree sp[sp[root].child[1]].child[0] 8:   9: struct SplayTree

HYSBZ 1588 营业额统计

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1588 题意:详见题面,中文 思路:平衡树的模板题. 可用Treap,Splay,Scapegoat Tree. [替罪羊树代码] #define _CRT_SECURE_NO_DEPRECATE #include<stdio.h> #include<string.h> #include<cstring> #include<algorithm> #in

BZOJ1588 营业额统计 splay tree

最基本的平衡树操作吧,第一次学splay的可以做一下 只需要插入,删除,旋转,求前驱,后继这5个操作吧 不喜欢用指针,用数组写的 <span style="color:#00cccc;">//HNOI2002营业额统计 #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define INF 1<<30 #define

BZOJ 1588 营业额统计

Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题.经济管理学上定义了一种最小波动值来衡量这种情况: 该天的最小波动值 当最小波动值越大

【BZOJ-1588】营业额统计 Splay

1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 12485  Solved: 4508[Submit][Status][Discuss] Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其

BZOJ1588 [HNOI2002]营业额统计 splay模板

1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 16189  Solved: 6482 [Submit][Status][Discuss] Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者

BZOJ1588 HNOI2002 营业额统计 [Splay入门题]

[HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 4128  Solved: 1305 Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业 额会出现一定的波动,当然一定的波动是能够接受

1588: [HNOI2002]营业额统计 splay tree

//http://www.lydsy.com/JudgeOnline/problem.php?id=1588 //题意:每读入一个数,在前面输入的数中找到一个与该数相差最小的一个,把所有的差值绝对值加起来并输出 1 #include "bits/stdc++.h" 2 using namespace std; 3 const int maxn = 100010; 4 const int INF = 0x3f3f3f3f; 5 struct SplayTreeNode 6 { 7 int

bzoj 1588营业额统计(HNOI 2002)

http://www.lydsy.com/JudgeOnline/problem.php?id=1588 我的第一颗splay, bottom-up的数组实现. 题意就是给你一组数,求每个数与在其前面且与其最相近的数的差值的绝对值. 考虑splay二叉搜索树的特性,每新插入一个节点,比它小且最靠近它的数在是左子树中的最大值,另一半同理. 代码借鉴自:http://blog.csdn.net/ACM_cxlove?viewmode=contents 1 #include <cstdio> 2 #