洛谷题解P4314CPU监控--线段树

题目链接

https://www.luogu.org/problemnew/show/P4314

https://www.lydsy.com/JudgeOnline/problem.php?id=3064

分析

其实我是在看吉司机线段树课件时看到这题很感兴趣就跑过来做

显然如果数据小一点可以用分块什么的比较好搞

但是这个数据范围可能用$log N$的数据结构更舒服一点

怎么搞呢?请阅读国家集训队2016论文集之《区间最值操作与历史最值问题——杭州学军中学 吉如一》,对,就是我们敬爱可亲的吉司机.

看不懂?实际上就是告诉我们维护6个$lazy$_$tag$:

1. $nmx$表示当前区间最大值,$add$表示当前区间加法标记,$set$表示当前区间赋值标记

2. $pmx$表示当前区间历史最大值,$padd$表示当前区间在下传此标记前时历史最大加法标记,$pset$表示当前区间在下传此标记前历史最大赋值标记

这样$lazy$_$tag$之间的合并就比较显然了

然后再结合论文食用,或是看代码理解一下

当然GXZlegend大佬使用吉司机的另一个方法也是可行的

http://www.cnblogs.com/GXZlegend/p/8315275.html

注意

我查错又查了一个小时

  • 注意不要把$-inf$写成$inf$

  • 在$pushdown$时思维一定要清晰,注意是哪些标记会对其他标记产生影响

代码

目前在luogu上rank 2在BZOJ上被吊打了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
#define ll long long
#define ri register int
using std::max;
const int inf=0x3f3f3f3f;
const int maxn=100005;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
int n;
int nmx[maxn<<2],add[maxn<<2],set[maxn<<2];
int pmx[maxn<<2],padd[maxn<<2],pset[maxn<<2];
int num[maxn];
int L,R,dta;
void build(int now,int l,int r){
set[now]=nmx[now]=pmx[now]=pset[now]=-inf;
padd[now]=add[now]=0;
if(l==r){
nmx[now]=pmx[now]=num[l];
return ;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
nmx[now]=pmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
return ;
}
inline void pushdown(int now){
if(padd[now]){
pmx[now<<1]=max(pmx[now<<1],nmx[now<<1]+padd[now]);
if(set[now<<1]!=-inf)
pset[now<<1]=max(pset[now<<1],set[now<<1]+padd[now]);
else
padd[now<<1]=max(padd[now<<1],add[now<<1]+padd[now]);
pmx[now<<1|1]=max(pmx[now<<1|1],nmx[now<<1|1]+padd[now]);
if(set[now<<1|1]!=-inf)
pset[now<<1|1]=max(pset[now<<1|1],set[now<<1|1]+padd[now]);
else
padd[now<<1|1]=max(padd[now<<1|1],add[now<<1|1]+padd[now]);
padd[now]=0;
}
if(pset[now]!=-inf){
pmx[now<<1]=max(pmx[now<<1],pset[now]);
pset[now<<1]=max(pset[now<<1],pset[now]);
pmx[now<<1|1]=max(pmx[now<<1|1],pset[now]);
pset[now<<1|1]=max(pset[now<<1|1],pset[now]);
pset[now]=-inf;
}
if(add[now]){
nmx[now<<1]+=add[now];
pmx[now<<1]=max(pmx[now<<1],nmx[now<<1]);
if(set[now<<1]!=-inf){
set[now<<1]+=add[now];
pset[now<<1]=max(pset[now<<1],set[now<<1]);
}
else {
add[now<<1]+=add[now];
padd[now<<1]=max(padd[now<<1],add[now<<1]);
}
nmx[now<<1|1]+=add[now];
pmx[now<<1|1]=max(pmx[now<<1|1],nmx[now<<1|1]);
if(set[now<<1|1]!=-inf){
set[now<<1|1]+=add[now];
pset[now<<1|1]=max(pset[now<<1|1],set[now<<1|1]);
}
else {
add[now<<1|1]+=add[now];
padd[now<<1|1]=max(padd[now<<1|1],add[now<<1|1]);
}
add[now]=0;
}
if(set[now]!=-inf){
nmx[now<<1]=set[now];
pmx[now<<1]=max(pmx[now<<1],nmx[now<<1]);
set[now<<1]=set[now];
pset[now<<1]=max(pset[now<<1],set[now<<1]);
nmx[now<<1|1]=set[now];
pmx[now<<1|1]=max(pmx[now<<1|1],nmx[now<<1|1]);
set[now<<1|1]=set[now];
pset[now<<1|1]=max(pset[now<<1|1],set[now<<1|1]);
set[now]=-inf;
add[now<<1]=add[now<<1|1]=0;
}
return ;
}
void update_add(int now,int l,int r){
if(L<=l&&r<=R){
nmx[now]+=dta;
pmx[now]=max(pmx[now],nmx[now]);
if(set[now]!=-inf){
set[now]+=dta;
pset[now]=max(pset[now],set[now]);
}
else{
add[now]+=dta;
padd[now]=max(padd[now],add[now]);
}
return ;
}
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid)update_add(now<<1,l,mid);
if(mid<R)update_add(now<<1|1,mid+1,r);
nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
return ;
}
void update_set(int now,int l,int r){
if(L<=l&&r<=R){
nmx[now]=dta;
pmx[now]=max(pmx[now],dta);
set[now]=dta;
pset[now]=max(pset[now],dta);
add[now]=0;
return ;
}
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid)update_set(now<<1,l,mid);
if(mid<R)update_set(now<<1|1,mid+1,r);
nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
return;
}
int query_now(int now,int l,int r){
if(L<=l&&r<=R){
return nmx[now];
}
int ans=-inf,mid=(l+r)>>1;
pushdown(now);
if(L<=mid)ans=max(ans,query_now(now<<1,l,mid));
if(mid<R)ans=max(ans,query_now(now<<1|1,mid+1,r));
nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
return ans;
}
int query_history(int now,int l,int r){
if(L<=l&&r<=R){
return pmx[now];
}
int ans=-inf,mid=(l+r)>>1;
pushdown(now);
if(L<=mid)ans=max(ans,query_history(now<<1,l,mid));
if(mid<R)ans=max(ans,query_history(now<<1|1,mid+1,r));
nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
return ans;
}
int q;
int main(){
int x,y,z;
char opt[5];
read(n);
for(ri i=1;i<=n;i++)read(num[i]);
build(1,1,n);
read(q);
while(q--){
scanf("%s",opt);
read(x),read(y);
L=x,R=y;
if(opt[0]=='Q'){
printf("%d\n",query_now(1,1,n));
}
else if(opt[0]=='A'){
printf("%d\n",query_history(1,1,n));
}
else if(opt[0]=='P'){
read(dta);
update_add(1,1,n);
}
else{
read(dta);
update_set(1,1,n);
}
}
return 0;
}