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