【Wannafly挑战赛10】D.小H的询问(线段树的区间合并)

记录一个菜逼的成长。。

题目链接
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

小H给你一个数组{a},要求支持以下两种操作:

  1. 0 l r(1<=l<=r<=n) ,询问区间[l,r]中权值和最大的有效子区间的权值和,一个子区间被认为是有效的当且仅当这个子区间中没有两个相邻的偶数或者奇数。

  2. 1 x v(1<=x<=n,109<=v<=109) ,将a[x]的值修改为v。

输入描述:
第一行读入两个正整数n,m(1<=n,m<=10^5)

第二行读入n个整数,第i个表示a[i](-10^9 <= a[i] <= 10^9)

接下来m行,每行三个数表示操作,描述见题目描述。

输出描述:
输出每个询问的答案。

分析

算是经典的线段树的区间合并。
可以说是模板题了吧。

先说结点的结构。
记录区间的左右边界的 l,r ;
记录区间 [l,r] 的所有数的和 sum
记录在区间 [l,r] 里最左边的有效区间,即包含左端点的有效区间的值 sl ,和最右边的有效区间的值 sr
记录区间 [l,r] 里有效区间的最大值 ans

重点在如何合并。
现在有两个区间 [l1,r1],[l2,r2]
ar1 al2 不互为偶数或奇数时,
两区间可以合并。
此时合并后的区间 [l1,r2] sl
max(sl1,sum1+sl2)
这里包含了两层意思。
如果区间 [l1,r1] 为有效区间, sum 为区间和, max 自然会取后值。
如果区间 [l1,r1] 不为有效区间, sum 会被设为-INF, max 自然会取前值。
同理 sr=max(sr2,sum2+sr1)
ans=max(max(ans1,ans2),sr1+sl2)

反之两区间不可以合并
sum 被设为-INF,与合并时的操作相对应
sl=sl1 , sr=sr2
ans=max(ans1,ans2)

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define fi first 
#define se second
#define cl(a,b) memset(a,b,sizeof(a))
#define clr clear()
#define lson t<<1,l,mid
#define rson t<<1|1,mid+1,r
#define seglen(t) (node[t].r-node[t].l+1)
typedef long long LL;
typedef pair<LL,LL> PLL;
typedef pair<int,int> PII;
const LL INF = 0x3f3f3f3f;
const int maxn = 100000 + 10;
LL a[maxn];
struct Node{
  int l,r;
  LL sl,sr;
  LL ans,sum;
  Node(){l = r = 0;sum = -INF * maxn;}
  Node operator + (const Node &ob)const {
    Node ret ;
    ret.l = l;ret.r = ob.r;
    if((a[r]^a[ob.l])&1) { 
      ret.sum = sum + ob.sum;
      ret.sl = max(sl,sum + ob.sl);
      ret.sr = max(ob.sr,ob.sum + sr);
      ret.ans = max(max(ans,ob.ans),sr + ob.sl);
    }
    else {
      ret.sum = -INF * maxn;
      ret.sl = sl;ret.sr = ob.sr;
      ret.ans = max(ans,ob.ans);
    }
    return ret;
  } 
}node[maxn<<2];
void pushup(int t)
{
  node[t] = node[t<<1] + node[t<<1|1];
}
void build(int t,int l,int r)
{
  node[t].l = l;
  node[t].r = r;
  node[t].sum = -INF * maxn;
  if (l == r) {
    node[t].sl = node[t].sr = node[t].ans = node[t].sum = a[l];
    return ;
  }
  int mid = (l + r) >> 1;
  build(lson);
  build(rson);
  pushup(t);
}
void update(int t,int ind,LL v)
{
  if(node[t].l == node[t].r) {
    node[t].sl = node[t].sr = node[t].ans = node[t].sum = v;
    return ;
  }
  int mid = (node[t].l + node[t].r) >> 1;
  if(ind <= mid)update(t<<1,ind,v);
  if(ind >  mid)update(t<<1|1,ind,v);
  pushup(t);
}
Node query(int t,int l,int r)
{
  if(node[t].l >= l && r >= node[t].r) {
    return node[t];
  }
  int mid = (node[t].l + node[t].r) >> 1;
  if(l >  mid)return query(t<<1|1,l,r);
  if(r <= mid)return query(t<<1,l,r);
  return query(t<<1,l,r) + query(t<<1|1,l,r);
}
int main()
{
  int n,m;
  while(~scanf("%d%d",&n,&m)) {
    for (int i = 1; i <= n; i++) scanf("%lld",a+i);
    build(1,1,n);
    while(m--) {
      int ope,l,r;
      scanf("%d%d%d",&ope,&l,&r);
      if(ope) {
        a[l] = r;
        update(1,l,(LL)r);
      }
      else {
        Node ret = query(1,l,r);
        printf("%lld\n",ret.ans);
      }
    }
  }
  return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值