HDU 5316

HDU 5316

题意是给一个数列,有两种操作,一是询问[L,R]的最大子序列和,二是改变某个位置的值。单点修改,区间查询,很显然的线段树。关键在于,询问时的最大子序列要求相邻元素的在原序列中的位置奇偶性不同。
序列的奇偶性根据首位和末位的奇偶性最多就四种情况,奇奇,偶偶,奇偶,偶奇。
那么线段树中的每个节点保存这四种序列的最大和即可,并注意合并。

#include<bits/stdc++.h>
#define LS (root<<1)
#define RS ((root<<1)|1)
#define LSON LS,l,mid
#define RSON RS,(mid+1),r
#define MID mid=((l+r)/2)
#define LL long long
#define mm(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1e5+5;
const LL Inf=1e18;
struct sum{
    LL odd_odd, odd_even, even_odd, even_even;
    sum(){odd_odd=-Inf; odd_even=-Inf; even_odd=-Inf; even_even=-Inf;}
};
sum s[maxn<<2];
LL a[maxn];
void pushup(int root){
    s[root].odd_odd=max(max(s[LS].odd_odd, s[RS].odd_odd), max(s[LS].odd_odd+s[RS].even_odd, s[LS].odd_even+s[RS].odd_odd));
    s[root].odd_even=max(max(s[LS].odd_even, s[RS].odd_even), max(s[LS].odd_odd+s[RS].even_even, s[LS].odd_even+s[RS].odd_even));
    s[root].even_odd=max(max(s[LS].even_odd, s[RS].even_odd), max(s[LS].even_odd+s[RS].even_odd, s[LS].even_even+s[RS].odd_odd));
    s[root].even_even=max(max(s[LS].even_even, s[RS].even_even), max(s[LS].even_even+s[RS].odd_even, s[LS].even_odd+s[RS].even_even));
}
void build(int root,int l,int r){
    s[root].odd_odd=s[root].odd_even=s[root].even_odd=s[root].even_even=-Inf;
    if(l==r){
        if(l%2)
            s[root].odd_odd=a[l];
        else
            s[root].even_even=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(LSON);
    build(RSON);
    pushup(root);
}
void update(int root,int l,int r,int pos,LL v){
    if(l==r){
        if(l%2)
            s[root].odd_odd=v;
        else
            s[root].even_even=v;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(LSON, pos, v);
    else update(RSON, pos, v);
    pushup(root);
}
sum unite(sum lsum, sum rsum){
    sum ret;
    ret.odd_odd=max(max(lsum.odd_odd, rsum.odd_odd), max(lsum.odd_odd+rsum.even_odd, lsum.odd_even+rsum.odd_odd));
    ret.odd_even=max(max(lsum.odd_even, rsum.odd_even), max(lsum.odd_even+rsum.odd_even, lsum.odd_odd+rsum.even_even));
    ret.even_odd=max(max(lsum.even_odd, rsum.even_odd), max(lsum.even_odd+rsum.even_odd, lsum.even_even+rsum.odd_odd));
    ret.even_even=max(max(lsum.even_even, rsum.even_even), max(lsum.even_even+rsum.odd_even, lsum.even_odd+rsum.even_even));
    return ret;
}
sum query(int root,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return s[root];
    }
    int mid=(l+r)>>1;
    sum lsum, rsum;
    if(L<=mid) lsum=query(LSON, L, R);
    if(R>mid) rsum=query(RSON, L, R);
    return unite(lsum,rsum);
}
int main(){
    int T, n, m;
    int op, L, R;
    LL v;

    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n, &m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        build(1,1,n);
        for(int i=0;i<m;i++){
            scanf("%d",&op);
            if(op==0){
                scanf("%d%d", &L, &R);
                sum ans=query(1,1,n,L,R);
                printf("%lld\n",max(max(ans.odd_odd, ans.odd_even), max(ans.even_even, ans.even_odd)));
            }else{
                scanf("%d%lld",&L, &v);
                update(1,1,n,L,v);
            }
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值