题目链接:#164. 【清华集训2015】V
大佬的博客:jefflyy
这个东西,,,诡异的标记下传。
一共有五种操作,区间加法,区间减法(减到0就不减了),区间覆盖,单点询问,单点历史最大值。
非常巧妙的使用了一个pair来进行标记。y=max(x+a,b)。
就是可以看做建立一个直角坐标系,其中x轴表示原数字,y轴表示修改后的数字,那么加法可以看做是
y
=
m
a
x
(
x
+
a
,
0
)
y=max(x+a,0)
y=max(x+a,0),减法可以看做为
y
=
m
a
x
(
x
−
a
,
0
)
y=max(x-a,0)
y=max(x−a,0),覆盖则为
y
=
a
或
者
y
=
m
a
x
(
−
o
o
,
a
)
y=a或者y=max(-oo,a)
y=a或者y=max(−oo,a),故可以将这三种标记统一成
(
x
+
a
,
b
)
(x+a,b)
(x+a,b)的形式。
那么假设原来的标记是
(
a
1
,
b
1
)
(a_1,b_1)
(a1,b1),这是来了一个
(
a
2
,
b
2
)
(a_2,b_2)
(a2,b2)的标记,那么可以合并为:
(
a
1
+
a
2
,
m
a
x
(
b
1
+
a
2
,
b
2
)
)
(a_1+a_2,max(b_1+a_2,b_2))
(a1+a2,max(b1+a2,b2))。
那么单点询问就是
m
a
x
(
x
+
a
,
b
)
max(x+a,b)
max(x+a,b)了。
历史最大值的话,我们只需要记录历史中出现过的最大标记即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+7;
const ll inf=1e18;
int a[maxn<<2|1];
pair<ll,ll> p[maxn<<2|1];//max(x+a,x=b);
pair<ll,ll> maxx[maxn<<2|1];
void build(int l,int r,int k){
p[k].first=maxx[k].first=0;
p[k].second=maxx[k].second=-inf;
if(l==r){
scanf("%d",&a[l]);
return ;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
}
void pushdown(int l,int r,int k){
if(p[k].first||p[k].second!=-inf){
maxx[k<<1].first=max(maxx[k<<1].first,maxx[k].first+p[k<<1].first);
maxx[k<<1].second=max(maxx[k<<1].second,max(maxx[k].first+p[k<<1].second,maxx[k].second));
maxx[k<<1|1].first=max(maxx[k<<1|1].first,maxx[k].first+p[k<<1|1].first);
maxx[k<<1|1].second=max(maxx[k<<1|1].second,max(maxx[k].first+p[k<<1|1].second,maxx[k].second));
p[k<<1].first=max(p[k<<1].first+p[k].first,-inf);
p[k<<1].second=max(p[k<<1].second+p[k].first,p[k].second);
p[k<<1|1].first=max(p[k<<1|1].first+p[k].first,-inf);
p[k<<1|1].second=max(p[k<<1|1].second+p[k].first,p[k].second);
p[k].first=maxx[k].first=0;
p[k].second=maxx[k].second=-inf;
}
}
void updata(int l,int r,int k,int L,int R,ll a,ll b){
if(l>=L&&r<=R){
p[k].first=max(p[k].first+a,-inf);
p[k].second=max(p[k].second+a,b);
maxx[k].first=max(maxx[k].first,p[k].first);
maxx[k].second=max(maxx[k].second,p[k].second);
return ;
}
pushdown(l,r,k);
int mid=(l+r)>>1;
if(L<=mid) updata(l,mid,k<<1,L,R,a,b);
if(R>mid) updata(mid+1,r,k<<1|1,L,R,a,b);
}
ll myfindid(int l,int r,int k,int id){
if(l==r) return max(a[l]+p[k].first,p[k].second);
pushdown(l,r,k);
int mid=(l+r)>>1;
if(id<=mid) return myfindid(l,mid,k<<1,id);
return myfindid(mid+1,r,k<<1|1,id);
}
ll myfindmax(int l,int r,int k,int id){
if(l==r) return max(a[l]+maxx[k].first,maxx[k].second);
pushdown(l,r,k);
int mid=(l+r)>>1;
if(id<=mid) return myfindmax(l,mid,k<<1,id);
return myfindmax(mid+1,r,k<<1|1,id);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
build(1,n,1);
int id,l,r,x;
while(m--){
scanf("%d",&id);
if(id==1){
scanf("%d%d%d",&l,&r,&x);
updata(1,n,1,l,r,x,0);
}
else if(id==2){
scanf("%d%d%d",&l,&r,&x);
updata(1,n,1,l,r,-x,0);
}
else if(id==3){
scanf("%d%d%d",&l,&r,&x);
updata(1,n,1,l,r,-inf,x);
}
else if(id==4){
scanf("%d",&l);
printf("%lld\n",myfindid(1,n,1,l));
}
else{
scanf("%d",&l);
printf("%lld\n",myfindmax(1,n,1,l));
}
}
return 0;
}