P4513 小白逛公园
P4513 小白逛公园
题目翻译:
给定一个长度为\(n\)初始序列,并进行\(m\)次询问,求一个区间类的最大连续子序列的大小,或者单点修改。
思路:
看到单点修改和区间查询可以很容易想到线段树,那如何用线段树来维护最大连续子序列。我们考虑给线段树维护以下参数:
\[$lm,rm,sum,mx$
\]
\(lm\)指当前区间从左边开始的最大连续序列,而\(rm\)指的是从右边开始。\(sum\)指当前序列的的和,而\(mx\)指当前序列的最大连续序列,也就是\(ans\)。考虑如何往上推:
\(1.\)一个区间的从左的最大连续序列可能是它左儿子的从左开始的最大连续序列,也有可能是最儿子的和在加上右儿子的从左开始的最大连续序列,而右边同理:
\[$tr[p].lm=max(tr[lc].lm,tr[lc].sum+tr[rc].lm);$ \]\[$tr[p].rm=max(tr[rc].rm,tr[rc].sum+tr[lc].rm);$ \]
\(2.\)若一个区间的最大连续子序列可以是它左儿子的或者右儿子的,但也有可能是做儿子的右最长加上右儿子的左最长,因此关系为:
\[$tr[p].mx=max(max(tr[lc].mx,tr[rc].mx),tr[rc].lm+tr[lc].rm);$ \]
\(3.\)和就不用说,就是左右儿子和之和:
\[$tr[p].sum=tr[lc].sum+tr[rc].sum;$ \]
这样就得到了根节点和左右儿子的关系:
void push_up(int p){
tr[p].sum=tr[lc].sum+tr[rc].sum;
tr[p].lm=max(tr[lc].lm,tr[lc].sum+tr[rc].lm);
tr[p].rm=max(tr[rc].rm,tr[rc].sum+tr[lc].rm);
tr[p].mx=max(max(tr[lc].mx,tr[rc].mx),tr[rc].lm+tr[lc].rm);
}
后面就不用说,普通的单点修改和区间查询,感觉蓝有点过头了
#include<bits/stdc++.h>
#define int long long
#define lc p<<1
#define rc p<<1|1
using namespace std;
const int N=5e5+10;
struct Tree{
int lm,rm,mx,sum;
}tr[N*4];
int a[N];
void push_up(int p){
tr[p].sum=tr[lc].sum+tr[rc].sum;
tr[p].lm=max(tr[lc].lm,tr[lc].sum+tr[rc].lm);
tr[p].rm=max(tr[rc].rm,tr[rc].sum+tr[lc].rm);
tr[p].mx=max(max(tr[lc].mx,tr[rc].mx),tr[rc].lm+tr[lc].rm);
}
void build(int p,int l,int r){
if(l==r){
tr[p].lm=tr[p].rm=tr[p].mx=tr[p].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(p);
}
Tree query(int p,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
return tr[p];
}
int mid=(l+r)>>1;
if(ll>mid)return query(rc,mid+1,r,ll,rr);
else{
if(rr<=mid)return query(lc,l,mid,ll,rr);
else{
Tree res,lt=query(lc,l,mid,ll,rr),rt=query(rc,mid+1,r,ll,rr);
res.lm=max(lt.lm,lt.sum+rt.lm);
res.rm=max(rt.rm,rt.sum+lt.rm);
res.mx=max(max(lt.mx,rt.mx),lt.rm+rt.lm);
res.sum=lt.sum+rt.sum;
return res;
}
}
}
void update(int p,int l,int r,int k,int num){
if(l==r){
//cout<<l<<endl;
tr[p].lm=tr[p].rm=tr[p].mx=tr[p].sum=num;
return;
}
int mid=(l+r)>>1;
if(k<=mid)update(lc,l,mid,k,num);
else update(rc,mid+1,r,k,num);
push_up(p);
}
signed main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);
while(m--){
int k;
cin>>k;
if(k==1){
int l,r;
cin>>l>>r;
if(l>r)swap(l,r);
cout<<query(1,1,n,l,r).mx<<endl;
}
if(k==2){
int k,num;
cin>>k>>num;
update(1,1,n,k,num);
}
}
}
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18682395
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步