hl uoj 1440. Can you answer on these queries III (蓝书刷题记录)

(线段树 单点修改 最大连续字段和)
在这里插入图片描述
维护 除区间和 左端点 右端点 外 lmax 表示以区间左端为起点的最大连续和 rmax 表示以区间右端点为起点的最大连续和。
可以知道 L 到 R 的最大连续子段和要么是子区间的最大连续和 要么是相邻的两个区间 前一个的rmax和 后一个区间的lmax 连接起来。

所以在 build 和 change 中修改即可。
但 在查询答案时 不仅要传递各个区间的最大连续子段和,lmax和rmax 也要记录和传递,因为最优的答案不一定是各个分隔开的区间的各个最大值的最大值。一些区间可以合并即 前一个的rmax和 后一个区间的lmax 连接起来。

#include<bits/stdc++.h>
 using namespace std;
const int MAXN=500050*2;
struct node{
  int l,r,maxx,w,lmax,rmax;
}t[MAXN*4+10];
int a[MAXN];
node J={0,0,-MAXN,-MAXN,-MAXN,-MAXN};
void build(int l,int r,int k)
{
   t[k].l=l; t[k].r=r;
   if(l==r)
   {
     t[k].w=a[l];
     t[k].lmax=t[k].w;
     t[k].rmax=t[k].w;
     t[k].maxx=t[k].w;
   	 return;
   }
   int mid=(l+r)/2;
   build(l,mid,k*2);
   build(mid+1,r,k*2+1);
   t[k].w=t[k*2].w+t[k*2+1].w;
   t[k].maxx=max(t[k*2].maxx,max(t[k*2+1].maxx,t[k*2].rmax+t[k*2+1].lmax));
   t[k].lmax=max(t[k*2].lmax,t[k*2].w+t[k*2+1].lmax);
   t[k].rmax=max(t[k*2+1].rmax,t[k*2+1].w+t[k*2].rmax);
}
node get(int p,int l,int r)
{
  if(l>t[p].r || r<t[p].l) return J;
  if(l<=t[p].l && r>=t[p].r) return t[p];
 //int mid=(t[p].l+t[p].r)/2;
  node L,R,ans;
  L=get(p*2,l,r);// 记录左子树
  R=get(p*2+1,l,r);//记录右子树
  ans.maxx=max(L.maxx,max(R.maxx,L.rmax+R.lmax));
  ans.lmax=max(L.lmax,L.w+R.lmax);
  ans.rmax=max(R.rmax,R.w+L.rmax);
  return ans;
}
void change(int k,int x,int v)
{
    if(t[k].l==t[k].r) 
	{ 
	  t[k].w=v;  
	  t[k].lmax=t[k].w;
      t[k].rmax=t[k].w;
      t[k].maxx=t[k].w;
	  return;
	}
	int mid=(t[k].l+t[k].r)/2;
    if(x<=mid) change(k*2,x,v);
	 else change(k*2+1,x,v); 
   t[k].maxx=max(t[k*2].maxx,max(t[k*2+1].maxx,t[k*2].rmax+t[k*2+1].lmax));
   t[k].lmax=max(t[k*2].lmax,t[k*2].w+t[k*2+1].lmax);
   t[k].rmax=max(t[k*2+1].rmax,t[k*2+1].w+t[k*2].rmax);
   t[k].w=t[k*2].w+t[k*2+1].w;
}
int main()
{
  freopen("b.in","r",stdin);
  freopen("b.out","w",stdout);
  int T,n;
  cin>>n>>T;
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  build(1,n,1);
  int opt,k1,k2;
  for(int i=1;i<=T;i++)
  {
  	scanf("%d%d%d",&opt,&k1,&k2);
  	if(opt==2) change(1,k1,k2);
  	if(opt==1) 
	 {
	  if(k1>k2){int tmp=k1; k1=k2; k2=tmp;}
	  printf("%d\n",get(1,k1,k2).maxx);
	 }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值