洛谷P2234[营业额统计]

戳这里看原题


 

这道题目一看就是要求在每个数前面的一段前缀中的前驱和后继。

很直白地就会想到二叉平衡树。

对于每一天的最小波动值只需要在二叉平衡树中插入节点的时候记录前驱和后继就可以很方便地算出来了。

所以总的来说,这道题就是一道模板题

先贴上treap的板子吧。。


 

 1 //treap
 2 #include <bits/stdc++.h>
 3 
 4 using namespace std;
 5 
 6 const int N = 32768;
 7 
 8 struct treap {
 9     int fa;
10     int s[2];
11     int wei;
12     int key;
13     
14     friend void check_print(const treap a) {
15         printf("!%d %d %d %d %d\n", a.fa, a.s[0], a.s[1], a.wei, a.key);
16     }
17 }tp[N + 1];
18 
19 int n;
20 int root, tot;
21 int ans;
22 
23 void rotate(int x) {
24     int y = tp[x].fa;
25     int z = tp[y].fa;
26     int c = tp[y].s[1] == x;
27     tp[x].fa = z;
28     if(z) tp[z].s[tp[z].s[1] == y] = x;
29     tp[tp[x].s[c ^ 1]].fa = y;
30     tp[y].s[c] = tp[x].s[c ^ 1];
31     tp[x].s[c ^ 1] = y;
32     tp[y].fa = x;
33     if(root == y) root = x;
34 }
35 
36 void set_up(int k, int f, int x) {
37     tp[k].key = x;
38     tp[k].wei = rand();
39     tp[k].fa = f;
40     tp[f].s[x > tp[f].key] = k;
41 }
42 
43 void up(int k) {
44     int f = tp[k].fa;
45     while(f && tp[f].wei > tp[k].wei) {
46         rotate(k);
47         f = tp[k].fa;
48     }
49 }
50 
51 int insert(int k, int x, int b, int s) {
52     if(tp[k].key == x) return 0;
53     if(tp[k].key > x) s = min(s, tp[k].key);
54     if(tp[k].key < x) b = max(b, tp[k].key);
55     if(!k || !tp[k].s[x > tp[k].key]) {
56         set_up(++tot, k, x);
57         up(tot);
58         if(!k) root = tot;
59         return min(abs(b - x), abs(s - x));
60     }
61     return insert(tp[k].s[tp[k].key < x], x, b, s);
62 }
63 
64 int main() {
65     srand(time(NULL));
66     int a;
67     scanf("%d%d", &n, &a);
68     ans += a;
69     insert(root, a, -2e9, 2e9);
70     for(int i = 1; i < n; i++) {
71         scanf("%d", &a);
72         ans += insert(root, a, -2e9, 2e9);
73     }
74     printf("%d\n", ans);
75     return 0;
76 }
View Code

 

但是C++的STL库中有一个神奇的东西——set。

它完美的(带了巨大常数)实现了高难度的红黑树。

既然有这样的好东西,为何不用呢?


 

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int N = 100000;
 6 
 7 int n;
 8 int a;
 9 int ans;
10 set<int>s;
11 
12 int main() {
13     scanf("%d", &n);
14     scanf("%d", &a);
15     s.insert(2e9);
16     s.insert(-2e9);
17     s.insert(2e9 + 1);
18     s.insert(-2e9 - 1);
19     s.insert(a);
20     ans += a;
21     for(int i = 1; i < n; i++) {
22         int k1 = 1e9, k2 = 1e9, k3 = 1e9, a;
23         scanf("%d", &a);
24         set<int>::iterator it = s.upper_bound(a);
25         k1 = abs(a - *it);
26         k2 = abs(a - *it), it--;
27         k3 = abs(a - *it), it++;
28         ans += min(k1, min(k2, k3));
29         s.insert(a);
30     }
31     printf("%d\n", ans);
32     return 0;
33 }
View Code

 

至于set的用法,这里给大家推荐一个个人认为归纳的比较好的博客,可以去借鉴一下。

戳这里

转载于:https://www.cnblogs.com/aha--CYJ/p/8395196.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值