「在更」初涉历史最值线段树

Posted antiquality

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「在更」初涉历史最值线段树相关的知识,希望对你有一定的参考价值。

历史最值线段树好像听上去很简单,多带几个参数就可以了? 吗?

历史最值线段树

正如其名,「历史最值线段树」记录的是区间内的历史最值。

HistoricalMaxVal == max(Tree[i].val)?

听上去是不是很简单啊?是不是我们每次记录一下max就好了啊?

好吧不讲这个正常人不会认可的想法了。

记录当前最大值mx?

那么我们记录一下当前区间的最大值$mx$,然后每一次操作这个区间的时候用$HistoricalMaxVal=max(mx+add)$更新一下怎么样?

是的,这样对于线段树单个节点来说正确性是有了。但是我们怎么向下传递呢?

我们都知道线段树区间操作为了效率是要$pushdown$操作的。但如果按照这种思路,我们只能够更新区间而无法向下传递!

可能有点抽象,举个例子:

 

a[]:1 2 3 4 5
add 1 5 15
add 1 5 -15
query 3 5

 

这里我们先对$[1,5]$加上15,再对$[1,5]$减去15,最后查询$[3,5]$的历史最大值。

如果对于每一个区间我们只记录$mx,hisMx$这两个数,上面例子里的前两个操作都只是对于线段树的root($[1,5]$这个区间)操作,并且最终记录下来$add=0,his=15$。可是$[1,5]$记录下来的正确的最大值又有什么用呢?我们查询的是$[3,5]$,这样一来查询出来的答案就变成$5$了。

 

 

几道例题

bzoj3064: Tyvj 1518 CPU监控

Description

Bob需要一个程序来监视CPU使用率。这是一个很繁琐的过程,为了让问题更加简单,Bob会慢慢列出今天会在用计算机时做什么事。
Bob会干很多事,除了跑暴力程序看视频之外,还会做出去玩玩和用鼠标乱点之类的事,甚至会一脚踢掉电源……这些事有的会让做这件事的这段时间内CPU使用率增加或减少一个值;有的事还会直接让CPU使用率变为一个值。
当然Bob会询问:在之前给出的事件影响下,CPU在某段时间内,使用率最高是多少。有时候Bob还会好奇地询问,在某段时间内CPU曾经的最高使用率是多少。
为了使计算精确,使用率不用百分比而用一个整数表示。
不保证Bob的事件列表出了莫名的问题,使得使用率为负………………

Input

第一行一个正整数T,表示Bob需要监视CPU的总时间。
然后第二行给出T个数表示在你的监视程序执行之前,Bob干的事让CPU在这段时间内每个时刻的使用率达已经达到了多少。
第三行给出一个数E,表示Bob需要做的事和询问的总数。
接下来E行每行表示给出一个询问或者列出一条事件:
Q X Y:询问从X到Y这段时间内CPU最高使用率
A X Y:询问从X到Y这段时间内之前列出的事件使CPU达到过的最高使用率
P X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率增加Z
C X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率变为Z
时间的单位为秒,使用率没有单位。
X和Y均为正整数(X<=Y),Z为一个整数。
从X到Y这段时间包含第X秒和第Y秒。
保证必要运算在有符号32位整数以内。 

Output

对于每个询问,输出一行一个整数回答。

HINT 

数据分布如下:
第1、2个数据保证T和E均小于等于1000
第3、4个数据保证只有Q类询问
第5、6个数据保证只有C类事件
第7、8个数据保证只有P类事件
全部数据保证T和E均小于等于100000

 


 

题目分析

虽然说是板子题但是调了一晚上……

先把代码挂这里

注释掉的部分不是调试部分,就是打挂的细节处理。

  1 #include<bits/stdc++.h>
  2 const int INF = 2147483647;
  3 const int maxn = 100035;
  4 
  5 struct node
  6 {
  7     int hisMx,mx;
  8     int cg,add,cgMx,addMx;
  9     bool ce;
 10 }f[maxn<<2];
 11 int n,m;
 12 
 13 int read()
 14 {
 15     int num = 0;
 16     char ch = getchar();
 17     bool fl = 0;
 18     for (; !isdigit(ch); ch = getchar())
 19         if (ch==-) fl = 1;
 20     for (; isdigit(ch); ch = getchar())
 21         num = (num<<1)+(num<<3)+ch-48;
 22     if (fl) num = -num;
 23     return num;
 24 }
 25 void pushup(int rt)
 26 {
 27     f[rt].mx = std::max(f[rt<<1].mx, f[rt<<1|1].mx);
 28     // f[rt].hisMx = std::max(f[rt].mx, f[rt].hisMx);
 29     f[rt].hisMx = std::max(f[rt<<1].hisMx, f[rt<<1|1].hisMx);
 30 }
 31 void pushdown(int rt)
 32 {
 33     // printf("pushdownINFO:
");
 34     for (int i=0; i<=1; i++)
 35     {
 36         int x = rt<<1|i;
 37         f[x].hisMx = std::max(f[x].hisMx, std::max(f[rt].cgMx, f[x].mx+f[rt].addMx));
 38         if (f[x].cg!=-INF) f[x].cgMx = std::max(f[x].cgMx, f[x].cg+f[rt].addMx);
 39         else f[x].addMx = std::max(f[x].addMx, f[x].add+f[rt].addMx);
 40         // if (f[rt].cg){
 41         //     f[x].add = 0;
 42         //     f[x].ce = 1, f[x].mx = f[x].cg = f[rt].cg;
 43         //     f[x].cgMx = std::max(f[x].cg, f[x].cgMx);
 44         // }
 45         // if (f[rt].add){
 46         //     f[x].add += f[rt].add;
 47         // }
 48         // f[x].hisMx = std::max(f[x].hisMx, std::max(f[x].cgMx, f[x].mx+f[x].addMx));
 49         if (f[rt].add){
 50             if (f[x].cg!=-INF) f[x].cg += f[rt].add;
 51             else f[x].add += f[rt].add;
 52             f[x].mx += f[rt].add;
 53         }
 54         // if (f[rt].ce){
 55         if (f[rt].cg!=-INF){
 56             f[x].mx = f[x].cg = f[rt].cg;
 57             f[x].add = 0;
 58         }
 59         f[x].addMx = std::max(f[x].addMx, f[x].add);
 60         f[x].cgMx = std::max(f[x].cgMx, std::max(f[x].cg, f[rt].cgMx));
 61         // printf("%d: addMx:%d cgMx:%d hisMx:%d
",i,f[x].addMx,f[x].cgMx,f[x].hisMx);
 62     }
 63     // puts("");
 64     f[rt].add = f[rt].addMx = 0;
 65     f[rt].ce = 0, f[rt].cg = f[rt].cgMx = -INF;
 66 }
 67 void build(int rt, int l, int r)
 68 {
 69     f[rt].cg = f[rt].cgMx = -INF;
 70     if (l==r){
 71         f[rt].hisMx = f[rt].mx = read();
 72         // f[rt].cg = f[rt].cgMx = -INF;
 73         return;
 74     }
 75     int mid = (l+r)>>1;
 76     build(rt<<1, l, mid), build(rt<<1|1, mid+1, r);
 77     pushup(rt);
 78     return;
 79 }
 80 int queryMx(int rt, int L, int R, int l, int r)
 81 {
 82     if (l!=r) pushdown(rt);
 83     if (L <= l&&r <= R) return f[rt].mx;
 84     int mid = (l+r)>>1, ret = -INF;
 85     if (L <= mid) ret = std::max(ret, queryMx(rt<<1, L, R, l, mid));
 86     if (R > mid) ret = std::max(ret, queryMx(rt<<1|1, L, R, mid+1, r));
 87     return ret;
 88 }
 89 int queryHis(int rt, int L, int R, int l, int r)
 90 {
 91     if (l!=r) pushdown(rt);
 92     if (L <= l&&r <= R) return f[rt].hisMx;
 93     int mid = (l+r)>>1, ret = -INF;
 94     if (L <= mid) ret = std::max(ret, queryHis(rt<<1, L, R, l, mid));
 95     if (R > mid) ret = std::max(ret, queryHis(rt<<1|1, L, R, mid+1, r));
 96     return ret;
 97 }
 98 void updateAdd(int rt, int L, int R, int l, int r, int c)
 99 {
100     if (l!=r) pushdown(rt);
101     if (L <= l&&r <= R){
102         f[rt].add += c, f[rt].mx += c;
103         // f[rt].addMx = std::max(f[rt].addMx, f[rt].add);
104         f[rt].addMx += c;
105         f[rt].hisMx = std::max(f[rt].mx, f[rt].hisMx);
106         return;
107     }
108     int mid = (l+r)>>1;
109     if (L <= mid) updateAdd(rt<<1, L, R, l, mid, c);
110     if (R > mid) updateAdd(rt<<1|1, L, R, mid+1, r, c);
111     pushup(rt);
112     return;
113 }
114 void updateCover(int rt, int L, int R, int l, int r, int c)
115 {
116     if (l!=r) pushdown(rt);
117     if (L <= l&&r <= R){
118         // f[rt].add = 0;
119         f[rt].ce = 1;
120         f[rt].cgMx = f[rt].mx = f[rt].cg = c;
121         f[rt].hisMx = std::max(f[rt].mx, f[rt].hisMx);
122         return;
123     }
124     int mid = (l+r)>>1;
125     if (L <= mid) updateCover(rt<<1, L, R, l, mid, c);
126     if (R > mid) updateCover(rt<<1|1, L, R, mid+1, r, c);
127     pushup(rt);
128     return;
129 }
130 int main()
131 {
132     n = read();
133     build(1, 1, n);
134     m = read();
135     while (m--)
136     {
137         char ch[5];
138         scanf("%s",ch);
139         int x = read(), y = read(), z;
140         if (ch[0]==Q)
141             printf("%d
",queryMx(1, x, y, 1, n));
142         else if (ch[0]==A)
143             printf("%d
",queryHis(1, x, y, 1, n));
144         else{
145             z = read();
146             if (ch[0]==P)
147                 updateAdd(1, x, y, 1, n, z);
148             else updateCover(1, x, y, 1, n, z);
149         }
150     }
151     return 0;
152 }

 

以上是关于「在更」初涉历史最值线段树的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3064Tyvj 1518 CPU监控 线段树维护历史最值

初涉值域线段树

数据结构吉司机线段树

线段树维护最值

线段树及其基本操作

(线段树) 单点更新,区间查询最值