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
", ans);
102     }
103     return 0;
104 }
原文地址:https://www.cnblogs.com/fightfordream/p/6053921.html