BZOJ 1588:营业额统计(Splay)
Posted Shadowdsp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于BZOJ 1588:营业额统计(Splay)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1588 [HNOI2002]营业额统计 splay模板
BZOJ1588 HNOI2002 营业额统计 [Splay入门题]