P14311 【MX-S8-T4】平衡三元组 题解
出题人题解,欢迎观看视频题解,打不开的把链接https://www.bilibili.com/video/BV1hhsfzYEdc/复制下来打开。
首先转化条件为
那么就是在区间
提示1:考虑固定
这个时候
于是可以快速得到一个
继续优化,观察
观察到:由于
根据这点,我们钦定
于是自然的想到一个特殊的
分析一下,到这个时候我们已经考虑了
这个时候已经考虑
如果
延续刚才的想法,我们先钦定
可以立刻意识到我们进入了一个和刚才相似的递归子结构,到这里我们处理了
提示2:尝试分析是否会继续递归吗?最多递归多少层?
直接分析
接下来
归纳一下
所以如果
总结一下只需要求区间最大值和其位置,修改只有区间加法,线段树即可解决。时间复杂度
#include<bits/stdc++.h>
#define NOBUG
// #define ONLINE_JUDGE
#define il inline __attribute((always_inline))
#ifdef NOBUG
#define dbg(...) fprintf (stderr, __VA_ARGS__)
#else
#define dbg(...) void()
#endif
using u32=unsigned int;
using i64=long long;
using u64=unsigned long long;
const i64 INF=0x3f3f3f3f3f3f3f3fll;
#define lc (p<<1)
#define rc (lc|1)
i64 tag[1000010<<2];
struct NODE{
i64 max;
int pos;
NODE operator + (const NODE &o) const{
i64 mx=std::max(max,o.max);
int p=0;
if(max==mx) p=pos;
if(o.max==mx) p=o.pos;
return {mx,p};
}
}tree[1000010<<2];
void down(int p,i64 x){
tree[p].max+=x;
tag[p]+=x;
}
void pushdown(int p){
down(lc,tag[p]),down(rc,tag[p]);
tag[p]=0;
}
void pushup(int p){
tree[p]=tree[lc]+tree[rc];
}
void read(int p,int l,int r){
if(l==r){
tree[p]={0,l};
scanf("%lld",&tree[p].max);
return;
}
int mid=(l+r)>>1;
read(lc,l,mid),read(rc,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int s,int t,int x){
if(s<=l&&r<=t) return down(p,x);
int mid=(l+r)>>1;
pushdown(p);
if(s<=mid) modify(lc,l,mid,s,t,x);
if(mid<t) modify(rc,mid+1,r,s,t,x);
pushup(p);
}
NODE qry(int p,int l,int r,int s,int t){
if(s<=l&&r<=t) return tree[p];
int mid=(l+r)>>1;
pushdown(p);
NODE res={-INF,0};
if(s<=mid) res=res+qry(lc,l,mid,s,t);
if(mid<t) res=res+qry(rc,mid+1,r,s,t);
return res;
}
int n;
NODE qry(int l,int r,char rev){
if(rev){
l=n-l+1,r=n-r+1;
std::swap(l,r);
}
if(l>r) return {-INF,0};
NODE res=qry(1,1,n,l,r);
if(rev) res.pos=n-res.pos+1;
return res;
}
int cnt=0;
i64 calc(int l,int r,char rev){
NODE n1=qry(l,r,rev),n2,n3;
i64 res=-INF;
n2=n1,n3=qry(n1.pos+1,r,rev);
while(n3.pos){
++cnt;
res=std::max(res,n1.max+qry(n2.pos+1,n3.pos-1,rev).max+n3.max);
n2=n3;
n3=qry(n2.pos+1,r,rev);
if(n2.max*2<=n1.max+n3.max){
res=std::max(res,n1.max+n2.max+n3.max);
break;
}
}
return res;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("d_6_4.in", "r", stdin);
freopen("name.out", "w", stdout);
#endif
int o,l,r,x,q;
scanf("%d%d",&n,&q);
read(1,1,n);
while(q--){
scanf("%d%d%d",&o,&l,&r);
if(o==1){
i64 res=std::max(calc(l,r,0),calc(n-r+1,n-l+1,1));
if(res<=-INF/2) puts("No");
else printf("%lld\n",res);
}else{
scanf("%d",&x);
modify(1,1,n,l,r,x);
}
}
return 0;
}