《扶苏的问题》题解
1.[ABC347C] Ideal Holidays题解
2.《扶苏的问题》题解
3.[ABC366C] Balls and Bag Query 题解4.[ABC366D] Cuboid Sum Query 题解5.P7706 文文的摄影布置 题解6.[ABC370C] Word Ladder 题解7.P11020 「LAOI-6」Radiation 题解8.P11019 「LAOI-6」[太阳]] 请使用最新版手机 QQ 体验新功能 题解9.[ABC371D] 1D Country 题解10.[ABC371D] 1D Country 线段树解法11.P1955 程序自动分析 题解12.[ABC376E] Max × Sum 题解13.[ABC379D] Home Garden 题解14.P11276 第一首歌 题解15.[ABC380C] Move Segment 题解《扶苏的问题》题解
原题传送门:P1253 扶苏的问题
PS:请先阅读完题面,在继续观看
题意概述:
对于给定的数列
1.change 将区间
2.add 将区间
3.query 查询区间
分析:
对于本题,为追求最佳时间复杂度,我们将使用两个懒标记,分别记录
对于改与加标记这两个标记,我们可以发现改标记的优先度要大于加标记(都覆盖了,你还加啥呀),于是对于
AC代码详解
#include<bits/stdc++.h>
#define ll long long
#define seq(q,w,e) for(int q=w;q<=e;q++)
using namespace std;
const ll maxn=1e6+10;
const ll maxx=4e6+10;
const ll inf=2e15; //首先,inf太小会出错
ll a[maxn],tree[maxx],tag1[maxx],tag2[maxx]; //tag1为加标记,tag2为改标记
ll ls(ll p){return p<<1;}
ll rs(ll p){return p<<1|1;}
void push_up(ll p){
tree[p]=max(tree[ls(p)],tree[rs(p)]); //求最大值的线段树维护
}
void build_tree(ll p,ll pl,ll pr){
tag1[p]=0;tag2[p]=-inf; //其次,tag1,tag2不赋初值也会出错
if(pl==pr){
tree[p]=a[pl];
return;
}
ll mid=(pl+pr)>>1;
build_tree(ls(p),pl,mid);
build_tree(rs(p),mid+1,pr);
push_up(p);
}
void add_tag(ll p,ll d){
tree[p]+=d;
tag1[p]+=d;
}
void change_tag(ll p,ll x){
tree[p]=x; //既然是修改,当然是直接覆盖啦
tag2[p]=x;
tag1[p]=0; //再来,tag1不归零还会出错
}
void push_down(ll p){ //先加后改,也会出错
if(tag2[p]!=-inf){ //注意,tag2数组的初始值为-inf
change_tag(ls(p),tag2[p]);
change_tag(rs(p),tag2[p]);
tag2[p]=-inf; //用完记得还原
}
if(tag1[p]){
add_tag(ls(p),tag1[p]);
add_tag(rs(p),tag1[p]);
tag1[p]=0;
}
}
void change(ll l,ll r,ll p,ll pl,ll pr,ll x){
if(l<=pl&&r>=pr){
change_tag(p,x);
return;
}
push_down(p); //别忘了下传标记,下同
ll mid=(pl+pr)>>1;
if(l<=mid) change(l,r,ls(p),pl,mid,x);
if(r>mid) change(l,r,rs(p),mid+1,pr,x);
push_up(p); //别忘了维护树,下同
}
void up_data(ll l,ll r,ll p,ll pl,ll pr,ll d){
if(l<=pl&&r>=pr){
add_tag(p,d);
return;
}
push_down(p);
ll mid=(pl+pr)>>1;
if(l<=mid) up_data(l,r,ls(p),pl,mid,d);
if(r>mid) up_data(l,r,rs(p),mid+1,pr,d);
push_up(p);
}
ll query(ll l,ll r,ll p,ll pl,ll pr){
if(l<=pl&&r>=pr)
return tree[p];
push_down(p);
ll mid=(pl+pr)>>1,res=-inf;
if(l<=mid) res=query(l,r,ls(p),pl,mid);
if(r>mid) res=max(res,query(l,r,rs(p),mid+1,pr));
return res;
}
ll n,m,op;
ll l,r,sum;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>m;
seq(i,1,n){
cin>>a[i];
}
build_tree(1,1,n); //不建树更会报错
seq(i,1,m){
cin>>op>>l>>r;
if(op==1){
cin>>sum;
change(l,r,1,1,n,sum);
}
if(op==2){
cin>>sum;
up_data(l,r,1,1,n,sum);
}
if(op==3){
cout<<query(l,r,1,1,n)<<"\n";
}
}
return 0;
}
总的来说,是一道不错的线段树版子题,不得不说,做完后对线段树的理解加深了许多。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】