BZOJ 1588:营业额统计(Splay)

http://www.lydsy.com/JudgeOnline/problem.php?id=1588

题意:中文题意。

思路:每一个点每一个点插入Splay,然后插入新的一个点之后,查这个节点的前驱和后继,即左子树最右边的点和右子树最左边的点。然后再从两个点中取个差值较小的就是答案了。要注意Rotate的时候一些细节(要给 rt 的父亲的父亲更新其孩子的值),还有Splay的细节:如果 rt 和 父节点都是要旋转相同方向,应该先旋转父亲节点再旋 rt,如果旋转不同方向就都是旋 rt。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <queue>
  8 #include <vector>
  9 using namespace std;
 10 #define INF 0x7fffffff
 11 #define N 40000
 12 struct node
 13 {
 14     int val, fa, son[2]; // val是节点权值,fa是父亲,son[0]是左儿子, son[1]是右儿子
 15 }tree[N];
 16 int cnt; // 节点数
 17
 18 void new_node(int f, int w, int kind)
 19 {
 20     cnt++;
 21     memset(tree[cnt].son, 0, sizeof(tree[cnt].son));
 22     tree[cnt].val = w;
 23     tree[cnt].fa = f;
 24     tree[f].son[kind] = cnt;
 25 }
 26
 27 void Rotate(int rt, int kind) // 旋转操作要注意更新 rt 的父亲的父亲的儿子的值
 28 {
 29     int y = tree[rt].fa;
 30     tree[y].son[kind^1] = tree[rt].son[kind];
 31     if(tree[rt].son[kind] != 0) tree[tree[rt].son[kind]].fa = y;
 32     tree[rt].fa = tree[y].fa;
 33     int z = tree[rt].fa;
 34     if(tree[z].son[0] == y) tree[z].son[0] = rt; // 就是这里
 35     else tree[z].son[1] = rt;
 36     tree[rt].son[kind] = y;
 37     tree[y].fa = rt;
 38 }
 39
 40 void Splay(int rt, int goal)
 41 {
 42     if(tree[rt].fa == goal) return ;
 43     while(tree[rt].fa != goal) {
 44         int y = tree[rt].fa;
 45         int z = tree[y].fa;
 46         int kind1 = rt == tree[y].son[0] ? 1 : 0;
 47         int kind2 = y == tree[z].son[0] ? 1 : 0;
 48         if(z == goal) {
 49             Rotate(rt, kind1);
 50         } else {
 51             if(kind1 == kind2) { // 连续左旋或者右旋
 52                 Rotate(y, kind2);
 53             } else {
 54                 Rotate(rt, kind1); // 先左后右或者先右后左
 55             }
 56             Rotate(rt, kind2);
 57         }
 58     }
 59 }
 60
 61 void Insert(int rt, int fa, int val, int kind)
 62 {
 63     if(rt == 0) {
 64         new_node(fa, val, kind);
 65         return ;
 66     }
 67     if(tree[rt].val >= val) Insert(tree[rt].son[0], rt, val, 0);
 68     else Insert(tree[rt].son[1], rt, val, 1);
 69 }
 70
 71 int Find(int rt, int kind)
 72 {
 73     if(tree[rt].son[kind] == 0) return rt; // 查先驱和后继节点
 74     Find(tree[rt].son[kind], kind);
 75 }
 76
 77 int main()
 78 {
 79     int n;
 80     while(~scanf("%d", &n)) {
 81         long long ans = 0;
 82         cnt = 0;
 83         for(int i = 1; i <= n; i++) {
 84             int x;
 85             scanf("%d", &x);
 86             if(i == 1) {
 87                 new_node(0, x, 0);
 88                 ans += x;
 89             } else {
 90                 Insert(cnt, 0, x, 0);
 91                 Splay(cnt, 0);
 92                 int pre = 0, suf = 0;
 93                 pre = Find(tree[cnt].son[0], 1);
 94                 suf = Find(tree[cnt].son[1], 0);
 95                 int prev = INF, sufv = INF;
 96                 if(pre != 0) prev = tree[pre].val;
 97                 if(suf != 0) sufv = tree[suf].val;
 98                 ans += min(abs(x - prev), abs(x - sufv));
 99             }
100         }
101         printf("%lld\n", ans);
102     }
103     return 0;
104 }
时间: 2024-10-01 07:45:43

BZOJ 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

BZOJ 1588 营业额统计

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

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 #

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】营业额统计 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

HYSBZ 1588 营业额统计 (Splay)

题意:给出一个公司每一天的营业额,求每天的最小波动值之和.该天的最小波动值= min { 绝对值| 该天以前某一天的营业额-该天的营业额 | }.第一天的最小波动值就是其自己. 思路:Splay伸展树的入门题,仅有splay,insert,rotate这三个主要的函数而已. 将一个数字(营业额)插入树中,并把其splay到根位置,然后其前驱和后继中离它较近的一个用来求最小波动值.注意可能没有前驱/后继.对第一个数特别处理. 注意:此题的数据有缺陷,读入营业额之前先将变量清零. 1 #includ

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