您的位置:首页 > 其它

【vijos】P1083 小白逛公园

2016-08-22 11:50 253 查看

【算法】线段树

【题解】

学自:https://vijos.org/p/1083/solution(wang_yanheng的回答)

回溯时维护一段区间的以下域:

  • sumL:从左端点起连续区间的最大和
  • sumR:从右端点起连续区间的最大和
  • sum:整段区间的和
  • subSum:最大子区间和

以上域在叶子节点中的值,都等于节点代表公园的评分
设当前节点为 x,左孩子为 l,右孩子为 r。则:

x.sumL = MAX(l.sumL, l.sum + r.sumL);
x.sumR = MAX(r.sumR, r.sum + l.sumR);
x.sum = l.sum + r.sum;
x.subSum = MAX(l.subSum, r.subSum, l.sumR + r.sumL);
以上计算过程可以写成函数,参数结构体,返回结构体。
查询时要返回结构体。
[/code]
#include<cstdio>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f,maxn=500010;
struct cyc{int lsum,rsum,sum,subsum;}t[maxn*3];
int a[maxn],L[maxn*3],R[maxn*3],n,m;
cyc calc(cyc a,cyc b)
{
cyc c;
c.lsum=max(a.lsum,a.sum+b.lsum);
c.rsum=max(b.rsum,b.sum+a.rsum);
c.sum=a.sum+b.sum;
c.subsum=max(a.subsum,max(b.subsum,a.rsum+b.lsum));
return c;
}
void build(int k,int l,int r)
{
L[k]=l;R[k]=r;
if(l==r)t[k]={a[l],a[l],a[l],a[l]};
else
{
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
t[k]=calc(t[k<<1],t[k<<1|1]);
}
}
void update(int k,int x,int num)
{
int left=L[k],right=R[k];
if(left==right)t[k]={num,num,num,num};
else
{
int mid=(left+right)>>1;
if(x<=mid)update(k<<1,x,num);
else update(k<<1|1,x,num);
t[k]=calc(t[k<<1],t[k<<1|1]);
}
}
cyc ask(int k,int l,int r)
{
int left=L[k],right=R[k];
if(l<=left&&right<=r)return t[k];
else
{
int mid=(left+right)>>1;
if(l>mid)return ask(k<<1|1,l,r);
if(r<=mid)return ask(k<<1,l,r);
return calc(ask(k<<1,l,r),ask(k<<1|1,l,r));
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int k,b,c;
scanf("%d%d%d",&k,&b,&c);
if(k==1)
{
if(b>c)swap(b,c);
printf("%d\n",ask(1,b,c).subsum);
}
else update(1,b,c);
}
}
View Code

 

 
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: