线段树你能回答这问题吗?
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树你能回答这问题吗?相关的知识,希望对你有一定的参考价值。
思路:
线段树节点需要存储六个信息,连续区间和的最大值,连续前缀和的最大值,连续后缀和的最大值
最大连续区间和可能横跨左子区间和右子区间,当横跨时,区间和就为左子区间的最大后缀和加上右子区间的最大前缀和,然后再和左右区间的最大连续区间和取最大值,即
t
r
[
u
]
.
m
x
=
m
a
x
(
m
a
x
(
t
r
[
u
<
<
1
]
.
m
x
,
t
r
[
u
<
<
1
∣
1
]
.
m
x
)
,
t
r
[
u
<
<
1
]
.
r
m
a
x
+
t
r
[
u
<
<
1
∣
1
]
.
l
m
a
x
)
;
tr[u].mx = max(max(tr[u<<1].mx,tr[u<<1|1].mx),tr[u<<1].rmax+tr[u<<1|1].lmax);
tr[u].mx=max(max(tr[u<<1].mx,tr[u<<1∣1].mx),tr[u<<1].rmax+tr[u<<1∣1].lmax);
计算最大前缀和和最大后缀和时,我们需要用到当前区间和的这个信息,需要定义sum这个信息,如果当前最大前缀和横跨的区间大于左子区间的长度,那么前缀和就为左子区间的总和加上右子区间的最大前缀和。计算最大后缀和时是同样的方法思路。即
t
r
[
u
]
.
l
m
a
x
=
m
a
x
(
t
r
[
u
<
<
1
]
.
s
u
m
+
t
r
[
u
<
<
1
∣
1
]
.
l
m
a
x
,
t
r
[
u
<
<
1
]
.
l
m
a
x
)
tr[u].lmax = max(tr[u<<1].sum+tr[u<<1|1].lmax,tr[u<<1].lmax)
tr[u].lmax=max(tr[u<<1].sum+tr[u<<1∣1].lmax,tr[u<<1].lmax)
t
r
[
u
]
.
r
m
a
x
=
m
a
x
(
t
r
[
u
<
<
1
]
.
r
m
a
x
+
t
r
[
u
<
<
1
∣
1
]
.
s
u
m
,
t
r
[
u
<
<
1
∣
1
]
.
r
m
a
x
)
tr[u].rmax = max(tr[u<<1].rmax+tr[u<<1|1].sum,tr[u<<1|1].rmax)
tr[u].rmax=max(tr[u<<1].rmax+tr[u<<1∣1].sum,tr[u<<1∣1].rmax)
建树时注意更新区间信息 [ l , r ] [l,r] [l,r],然后还需要向上更新值(由子节点更新父节点)
询问的时候,如果区间横跨左右两个子区间,需要取左子区间的后缀和和右子区间的前缀和求,因此节点的所有的信息都要更新(需要用到之前更新过的节点信息)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
int n,m;
int w[N];
struct node
{
int l,r;
int mx,lmax,rmax,sum;
}tr[N * 4];
void pushup(int u)
{
tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
tr[u].lmax = max(tr[u<<1].sum+tr[u<<1|1].lmax,tr[u<<1].lmax);
tr[u].rmax = max(tr[u<<1].rmax+tr[u<<1|1].sum,tr[u<<1|1].rmax);
tr[u].mx = max(max(tr[u<<1].mx,tr[u<<1|1].mx),tr[u<<1].rmax+tr[u<<1|1].lmax);
}
void build(int u,int l,int r)
{
if(l==r) tr[u] = {l,r,w[r],w[r],w[r],w[r]};
else
{
tr[u] = {l,r};
int mid = tr[u].l + tr[u].r >> 1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
}
node query(int u,int l,int r)
{
if(tr[u].l>=l && tr[u].r<=r) return tr[u];
else
{
int mid = tr[u].l + tr[u].r >> 1;
if(r<=mid) return query(u<<1,l,r);
else if(l>mid) return query(u<<1|1,l,r);
else
{
auto left = query(u<<1,l,r);
auto right = query(u<<1|1,l,r);
node res;
res.sum = left.sum + right.sum;
res.lmax = max(left.sum+right.lmax,left.lmax);
res.rmax = max(left.rmax+right.sum,right.rmax);
res.mx = max(max(left.mx,right.mx),left.rmax+right.lmax);
return res;
}
}
}
void modify(int u,int x,int v)
{
if(tr[u].l==x && tr[u].r==x) tr[u]={x,x,v,v,v,v};
else
{
int mid = tr[u].l + tr[u].r >> 1;
if(x<=mid) modify(u<<1,x,v);
else modify(u<<1|1,x,v);
pushup(u);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
int k,x,y;
while(m--)
{
scanf("%d%d%d",&k,&x,&y);
if(k==1)
{
if(x>y) swap(x,y);
printf("%d\\n",query(1,x,y).mx);
}
else modify(1,x,y);
}
return 0;
}
以上是关于线段树你能回答这问题吗?的主要内容,如果未能解决你的问题,请参考以下文章