HDU 5316 Magician(线段树 区间合并)

题意:给你n(n<=10^5)个数ai(-10^9<=ai<=10^9)。要求从这里面取出它的序列,这些序列满足下标奇偶相间,求某段区间的这种序列的最大和值。

分析:最初没读懂题意。。。。 一看数据范围和查询方式,肯定和线段树相关,问题的要求又有点像DP。分析知道,其实就是求线段树的区间合并问题,取出的序列只可能是以奇数开头奇数结尾,奇数开头偶数结尾,偶数开头偶数结尾,偶数开头奇数结尾。用jj,jo,oo,oj表示。当合并的适合考虑这四种情况就是可以了。

jj=max(l.jj ,r.jj,  l.jj+r.oj,   l.jo+r.jo);其他依次类推

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
using namespace std;
#define maxn 200005
#define inff 0x7FFFFFFFFFFFFFFF
typedef __int64 LL;
LL a[maxn];
int n,m;
 LL max(LL x,LL y)
{
    return x>y?x:y;
}
 LL max(LL x,LL y,LL z,LL w)
{
    return max(max(x,y),max(z,w));
}
struct node
{
    int l,r;
    LL oo,jj,jo,oj;
}tr[maxn<<2];
inline LL add(LL x,LL y)
{
    if(x==-inff||y==-inff)return -inff;
    else return x+y;
}
void pushup(int id)
{
  tr[id].jj=max(add(tr[id*2].jo,tr[id*2+1].jj),add(tr[id*2].jj,tr[id*2+1].oj),tr[id*2].jj,tr[id*2+1].jj);
  tr[id].oo=max(add(tr[id*2].oj,tr[id*2+1].oo),add(tr[id*2].oo,tr[id*2+1].jo),tr[id*2].oo,tr[id*2+1].oo);
  tr[id].jo=max(add(tr[id*2].jj,tr[id*2+1].oo),add(tr[id*2].jo,tr[id*2+1].jo),tr[id*2].jo,tr[id*2+1].jo);
  tr[id].oj=max(add(tr[id*2].oo,tr[id*2+1].jj),add(tr[id*2].oj,tr[id*2+1].oj),tr[id*2].oj,tr[id*2+1].oj);
}
void build(int id,int l,int r)
{
    tr[id].l=l;
    tr[id].r=r;
    tr[id].jj=tr[id].oo=-inff;
     tr[id].oj=tr[id].jo=-inff;
    if(l==r)
    {
        if(l%2!=0)
        {
            tr[id].jj=a[l];
            tr[id].oo=tr[id].jo=tr[id].oj=-inff;
        }
        else
        {
            tr[id].oo=a[l];
            tr[id].jj=tr[id].jo=tr[id].oj=-inff;
        }
    }
    else
    {
        int mid=(l+r)/2;
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        pushup(id);
    }
}
void update(int id,int pos,LL val)
{
    if(tr[id].l==tr[id].r)
    {
        if(tr[id].l%2!=0)
        {
            tr[id].jj=val;
            tr[id].oo=tr[id].jo=tr[id].oj=-inff;
        }
        else
        {
            tr[id].oo=val;
            tr[id].jj=tr[id].jo=tr[id].oj=-inff;
        }
    }
    else
    {
        int mid=(tr[id].l+tr[id].r)/2;
        if(pos<=mid)update(id*2,pos,val);
        else update(id*2+1,pos,val);
        pushup(id);
    }
}
node query(int id,int l,int r)
{
    if(l<=tr[id].l&&tr[id].r<=r)
    {
        return tr[id];
    }
    else
    {
        int mid=(tr[id].l+tr[id].r)/2;
        if(r<=mid)return query(id*2,l,r);
        else if(l>mid)return query(id*2+1,l,r);
        else
        {
            node a=query(id*2,l,r);
            node b=query(id*2+1,l,r);
            node c;
            c.jj=max(a.jj,b.jj,add(a.jo,b.jj),add(a.jj,b.oj));
            c.oo=max(a.oo,b.oo,add(a.oj,b.oo),add(a.oo,b.jo));
            c.jo=max(a.jo,b.jo,add(a.jj,b.oo),add(a.jo,b.jo));
            c.oj=max(a.oj,b.oj,add(a.oo,b.jj),add(a.oj,b.oj));
            return c;
        }
    }
}
int main()
{
    int t,i;
    //cout<<inff<<endl;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
            scanf("%I64d",&a[i]);
        }
        build(1,1,n);
        //cout<<tr[1].jj<<" "<<tr[1].oo<<" "<<tr[1].oj<<endl;
        for(i=1;i<=m;i++)
        {
            int pos;
            LL val;
            int c,l,r;
            scanf("%d",&c);
            if(c==1)
            {
                scanf("%d%I64d",&pos,&val);
                update(1,pos,val);
            }
            else
            {
                scanf("%d%d",&l,&r);
                node ans=query(1,l,r);
                printf("%I64d\n",max(ans.jj,ans.jo,ans.oo,ans.oj));
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值