#C240215A. 线段树3
前言(Front talk)
网址(Website)
题目(Problem)
题目背景
题目描述
1 l r k
:对于所有的,将 加上 ( 可以为负数)。 2 l r v
:对于所有的,将 变成 。 3 l r
:求。 4 l r
:对于所有的,求 的最大值。 5 l r
:对于所有的,求 的最大值。
输入格式
输出格式
样例
输入
5 6
1 2 3 4 5
3 2 5
1 1 3 3
4 2 4
2 3 4 1
5 1 5
3 1 4
输出
14
6
6
11
提示
样例说明
操作次数 | 输入内容 | 操作 | 数列 | 输出结果 |
---|---|---|---|---|
0 | ||||
1 | 3 2 5 | 求出 | 14 | |
2 | 1 1 3 3 | 将 | ||
3 | 4 2 4 | 求出 | 6 | |
4 | 2 3 4 1 | 将 | ||
5 | 5 1 5 | 求出 | 6 | |
6 | 3 1 4 | 求出 | 11 |
数据规模与约定
- 对于测试点
,满足 ; - 对于测试点
,满足 ; - 对于测试点
,满足 ; - 对于全部测试数据,保证
, , , , , 。
提示
本题输入量较大,请使用合理高效的读入方法。
题解(Solution)
思路:
pushdown
下传的值和其下传的历史最大值。
add
操作对 min
操作的影响来实现修改,但是最后发现在 pushdown
的时候会出现问题—— add
操作和 min
操作的先后会影响到add(1,n,5),min(1,n,2)
与 min(1,n,2),add(1,n,5)
,虽然对于add
可以直接加在 to_min
上),但是这个先后顺序在进行 pushdown
时会被无视,导致历史值变大。
min
操作,转换为单点修改当前区间的最大值(大概是这个意思),将加减操作分解为对当前的最大值的修改和对其余值的修改,那么当我们找到一个区间满足要取最小值的
总的来说:
需要这些变量:
:当前区间的和 :当前区间的个数(即 ) :当前区间的最大值 :当前区间的次大值 :当前区间最大值的个数 :当前区间历史最大值 :最大值的加减懒标记 :除了最大值以外的值的加减懒标记 :最大值的历史最大加减懒标记 :除了最大值以外的值的历史最大加减懒标记
上传:
注意最大值的更新与最大值个数的记录:
void pushup(Tr &T,Tr L,Tr R){
T.sum=L.sum+R.sum;
T.mx1=max(L.mx1,R.mx1);
if(L.mx1==R.mx1){
T.mx2=max(L.mx2,R.mx2);
T.cmx=L.cmx+R.cmx;
}else{
T.mx2=max(min(L.mx1,R.mx1),max(L.mx2,R.mx2));
T.cmx=L.mx1>R.mx1?L.cmx:R.cmx;
}T.hmx=max(L.hmx,R.hmx);
// cerr<<"PUSHUP:"<<T.sum<<' '<<T.mx1<<' '<<T.mx2<<' '<<T.hmx<<'\n';
}
建树:
代码如下,正常建树就可以了:
#define mid (l+r>>1)
#define ls (p<<1)
#define rs (p<<1|1)
struct Tr{
int sum,siz,cmx;
int mx1,mx2,hmx;
int ad1,had1,ad2,had2;
}tr[N<<2|3];
void build(int p,int l,int r){
tr[p]={a[l],r-l+1,1,a[l],-inf,a[l],0,0,0,0};
if(l==r) return;
build(ls,l,mid),build(rs,mid+1,r);
pushup(tr[p],tr[ls],tr[rs]);
}
下传:
下传时先看修改:
void modify(int p,int k1,int hk1,int k2,int hk2){
tr[p].sum += (tr[p].cmx * k1 + (tr[p].siz - tr[p].cmx)*k2);
tr[p].hmx = max(tr[p].hmx, tr[p].mx1 + hk1);
tr[p].mx1 += k1;
if(tr[p].mx2!=-inf) tr[p].mx2+=k2;
tr[p].had1 = max(tr[p].had1, tr[p].ad1 + hk1);
tr[p].ad1 += k1;
tr[p].had2 = max(tr[p].had2, tr[p].ad2 + hk2);
tr[p].ad2 += k2;
}
pushdown
可以判断最大值在哪里,从而跟踪修改,如果这个区间不是最大值,那么直接下传其余值的标记,代码如下:
void pushdown(int p){
int maxn = max(tr[ls].mx1, tr[rs].mx1);
if(tr[ls].mx1 == maxn)
modify(ls,tr[p].ad1,tr[p].had1,tr[p].ad2,tr[p].had2);
else modify(ls,tr[p].ad2,tr[p].had2,tr[p].ad2,tr[p].had2);
if(tr[rs].mx1 == maxn)
modify(rs,tr[p].ad1,tr[p].had1,tr[p].ad2,tr[p].had2);
else modify(rs,tr[p].ad2,tr[p].had2,tr[p].ad2,tr[p].had2);
tr[p].ad1 = tr[p].had1 = tr[p].ad2 = tr[p].had2 = 0;
}
更新:
直接上代码:
void update_sum(int p,int l,int r,int L,int R,int k){
if(L<=l && r<=R) return modify(p,k,k,k,k);
pushdown(p);
if(L<=mid) update_sum(ls,l,mid,L,R,k);
if(R>mid) update_sum(rs,mid+1,r,L,R,k);
pushup(tr[p],tr[ls],tr[rs]);
}
void update_min(int p,int l,int r,int L,int R,int v){
if(tr[p].mx1<=v) return;
if(L<=l && r<=R && tr[p].mx2<v)
return modify(p,v-tr[p].mx1,v-tr[p].mx1,0,0);
pushdown(p);
if(L<=mid) update_min(ls,l,mid,L,R,v);
if(R>mid) update_min(rs,mid+1,r,L,R,v);
pushup(tr[p],tr[ls],tr[rs]);
}
询问:
这里直接一次搞定,可能需要理解一下这种打法:
Tr ask(int p,int l,int r,int L,int R){
if(L<=l && r<=R) return tr[p];pushdown(p);
if(R<=mid) return ask(ls,l,mid,L,R);
if(L>mid) return ask(rs,mid+1,r,L,R);
Tr T;return pushup(T,ask(ls,l,mid,L,mid),ask(rs,mid+1,r,mid+1,R)),T;
}
代码(Code)
50pts
#include<bits/stdc++.h>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define int long long
inline int input(){int x;return cin>>x,x;}
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 501234;
int n,m,a[N];
#define mid (l+r>>1)
#define ls (p<<1)
#define rs (p<<1|1)
struct Tr{
int sum,siz;
int mx1,mx2,cmx;
int add,had,tmn;
int hmx;
}tr[N<<2|3];
void pushup(Tr &T,Tr L,Tr R){
T.sum=L.sum+R.sum;
T.mx1=max(L.mx1,R.mx1);
if(L.mx1==R.mx1){
T.mx2=max(L.mx2,R.mx2);
T.cmx=L.cmx+R.cmx;
}else{
T.mx2=max(min(L.mx1,R.mx1),max(L.mx2,R.mx2));
T.cmx=L.mx1>R.mx1?L.cmx:R.cmx;
}T.hmx=max(L.hmx,R.hmx);
}
void build(int p,int l,int r){
tr[p]={a[l],r-l+1,a[l],-inf,1,0,0,inf,a[l]};
if(l==r) return;
build(ls,l,mid),build(rs,mid+1,r);
pushup(tr[p],tr[ls],tr[rs]);
}
void push_add(int p,int k,int hk){
tr[p].hmx=max(tr[p].hmx,tr[p].mx1+hk);
tr[p].had=max(tr[p].had,tr[p].add+hk),
tr[p].sum+=tr[p].siz*k;
tr[p].mx1+=k,tr[p].mx2+=tr[p].mx2==-inf?0:k;
tr[p].add+=k,tr[p].tmn+=tr[p].tmn==inf?0:k;
}
void push_min(int p,int v){
if(tr[p].mx1 <= v) return;
tr[p].sum+=(v-tr[p].mx1)*tr[p].cmx;
tr[p].mx1=tr[p].tmn=v;
}
void pushdown(int p){
if(tr[p].add || tr[p].had)
push_add(ls,tr[p].add,tr[p].had),
push_add(rs,tr[p].add,tr[p].had);
if(tr[p].tmn!=inf)
push_min(ls,tr[p].tmn);
push_min(rs,tr[p].tmn);
tr[p].add=tr[p].had=0;tr[p].tmn=inf;
}
void update_sum(int p,int l,int r,int L,int R,int k){
if(L<=l && r<=R) return push_add(p,k,max(0ll,k));
pushdown(p);
if(L<=mid) update_sum(ls,l,mid,L,R,k);
if(R>mid) update_sum(rs,mid+1,r,L,R,k);
pushup(tr[p],tr[ls],tr[rs]);
}
void update_min(int p,int l,int r,int L,int R,int v){
if(tr[p].mx1<=v) return;
if(L<=l && r<=R && tr[p].mx2<v) return push_min(p,v);
pushdown(p);
if(L<=mid) update_min(ls,l,mid,L,R,v);
if(R>mid) update_min(rs,mid+1,r,L,R,v);
pushup(tr[p],tr[ls],tr[rs]);
}
Tr ask(int p,int l,int r,int L,int R){
if(L<=l && r<=R) return tr[p];pushdown(p);
if(R<=mid) return ask(ls,l,mid,L,R);
if(L>mid) return ask(rs,mid+1,r,L,R);
Tr T;return pushup(T,ask(ls,l,mid,L,mid),ask(rs,mid+1,r,mid+1,R)),T;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;For(i,1,n) a[i]=input();
int Tim=clock();build(1,1,n);
while(m--){
int opt=input(),l=input(),r=input(),k;
if(opt==1) update_sum(1,1,n,l,r,k=input());
if(opt==2) update_min(1,1,n,l,r,k=input());
if(opt==3) cout<<ask(1,1,n,l,r).sum<<'\n';
if(opt==4) cout<<ask(1,1,n,l,r).mx1<<'\n';
if(opt==5) cout<<ask(1,1,n,l,r).hmx<<'\n';
}return cerr<<"TIME:"<<(clock()-Tim)/1000.,0;
}
100pts
#include<bits/stdc++.h>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define int long long
inline int input(){int x;return cin>>x,x;}
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 501234;
int n,m,a[N];
#define mid (l+r>>1)
#define ls (p<<1)
#define rs (p<<1|1)
struct Tr{
int sum,siz,cmx;
int mx1,mx2,hmx;
int ad1,had1,ad2,had2;
}tr[N<<2|3];
void pushup(Tr &T,Tr L,Tr R){
T.sum=L.sum+R.sum;
T.mx1=max(L.mx1,R.mx1);
if(L.mx1==R.mx1){
T.mx2=max(L.mx2,R.mx2);
T.cmx=L.cmx+R.cmx;
}else{
T.mx2=max(min(L.mx1,R.mx1),max(L.mx2,R.mx2));
T.cmx=L.mx1>R.mx1?L.cmx:R.cmx;
}T.hmx=max(L.hmx,R.hmx);
}
void build(int p,int l,int r){
tr[p]={a[l],r-l+1,1,a[l],-inf,a[l],0,0,0,0};
if(l==r) return;
build(ls,l,mid),build(rs,mid+1,r);
pushup(tr[p],tr[ls],tr[rs]);
}
void modify(int p,int k1,int hk1,int k2,int hk2){
tr[p].sum += (tr[p].cmx * k1 + (tr[p].siz - tr[p].cmx)*k2);
tr[p].hmx = max(tr[p].hmx, tr[p].mx1 + hk1);
tr[p].mx1 += k1;
if(tr[p].mx2!=-inf) tr[p].mx2+=k2;
tr[p].had1 = max(tr[p].had1, tr[p].ad1 + hk1);
tr[p].ad1 += k1;
tr[p].had2 = max(tr[p].had2, tr[p].ad2 + hk2);
tr[p].ad2 += k2;
}
void pushdown(int p){
int maxn = max(tr[ls].mx1, tr[rs].mx1);
if(tr[ls].mx1 == maxn)
modify(ls,tr[p].ad1,tr[p].had1,tr[p].ad2,tr[p].had2);
else modify(ls,tr[p].ad2,tr[p].had2,tr[p].ad2,tr[p].had2);
if(tr[rs].mx1 == maxn)
modify(rs,tr[p].ad1,tr[p].had1,tr[p].ad2,tr[p].had2);
else modify(rs,tr[p].ad2,tr[p].had2,tr[p].ad2,tr[p].had2);
tr[p].ad1 = tr[p].had1 = tr[p].ad2 = tr[p].had2 = 0;
}
void update_sum(int p,int l,int r,int L,int R,int k){
if(L<=l && r<=R) return modify(p,k,k,k,k);
pushdown(p);
if(L<=mid) update_sum(ls,l,mid,L,R,k);
if(R>mid) update_sum(rs,mid+1,r,L,R,k);
pushup(tr[p],tr[ls],tr[rs]);
}
void update_min(int p,int l,int r,int L,int R,int v){
if(tr[p].mx1<=v) return;
if(L<=l && r<=R && tr[p].mx2<v)
return modify(p,v-tr[p].mx1,v-tr[p].mx1,0,0);
pushdown(p);
if(L<=mid) update_min(ls,l,mid,L,R,v);
if(R>mid) update_min(rs,mid+1,r,L,R,v);
pushup(tr[p],tr[ls],tr[rs]);
}
Tr ask(int p,int l,int r,int L,int R){
if(L<=l && r<=R) return tr[p];pushdown(p);
if(R<=mid) return ask(ls,l,mid,L,R);
if(L>mid) return ask(rs,mid+1,r,L,R);
Tr T;return pushup(T,ask(ls,l,mid,L,mid),ask(rs,mid+1,r,mid+1,R)),T;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;For(i,1,n) a[i]=input();
int Tim=clock();build(1,1,n);
while(m--){
int opt=input(),l=input(),r=input(),k;
if(opt==1) update_sum(1,1,n,l,r,k=input());
if(opt==2) update_min(1,1,n,l,r,k=input());
if(opt==3) cout<<ask(1,1,n,l,r).sum<<'\n';
if(opt==4) cout<<ask(1,1,n,l,r).mx1<<'\n';
if(opt==5) cout<<ask(1,1,n,l,r).hmx<<'\n';
}return cerr<<"TIME:"<<(clock()-Tim)/1000.,0;
}