HDU 5316 Magician (区结合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5316


题意:给出一个大小为n的区间,2种操作,更新某一个点的值,或者查询[l,r]区间的“最大值序列”(要求该序列的下标奇偶相间)



思路:线段树的单点更新和区间合并可以实现题目要求,我们维护4个数据就好,查询的比较特殊

(1).区间里最大的以奇数开头和以奇数结尾的序列

(2).区间里最大的以偶数开头和以偶数结尾的序列

(3).区间里最大的以奇数开头和以偶数结尾的序列

(4).区间里最大的以偶数开头和以奇数结尾的序列



#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
#define maxn 100030
#define inf 100000000030
#define data tree
using namespace std;

struct Tree
{
    int l,r;
    LL eo,ee,oo,oe;
}tree[maxn*5];

LL s[maxn];

void pushup(int root)
{
    tree[root].ee=max(tree[root<<1].eo+tree[root<<1|1].ee,tree[root<<1].ee+tree[root<<1|1].oe);
    tree[root].ee=max(tree[root].ee,tree[root<<1].ee);
    tree[root].ee=max(tree[root].ee,tree[root<<1|1].ee);

    tree[root].oo=max(tree[root<<1].oe+tree[root<<1|1].oo,tree[root<<1].oo+tree[root<<1|1].eo);
    tree[root].oo=max(tree[root].oo,tree[root<<1].oo);
    tree[root].oo=max(tree[root].oo,tree[root<<1|1].oo);

    tree[root].eo=max(tree[root<<1].eo+tree[root<<1|1].eo,tree[root<<1].ee+tree[root<<1|1].oo);
    tree[root].eo=max(tree[root].eo,tree[root<<1].eo);
    tree[root].eo=max(tree[root].eo,tree[root<<1|1].eo);

    tree[root].oe=max(tree[root<<1].oe+tree[root<<1|1].oe,tree[root<<1].oo+tree[root<<1|1].ee);
    tree[root].oe=max(tree[root].oe,tree[root<<1].oe);
    tree[root].oe=max(tree[root].oe,tree[root<<1|1].oe);
}

void build(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    if (tree[root].l==tree[root].r)
    {
        if (l%2==0)
            tree[root].oo=s[l];
        else
            tree[root].ee=s[l];



        return;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    pushup(root);

}



void update(int root,int p,int val)
{

    if (tree[root].l==tree[root].r)
    {
        if (tree[root].l%2==0)
            tree[root].oo=val;
        else
            tree[root].ee=val;
        return;
    }

    int mid=(tree[root].l+tree[root].r)>>1;
    if (mid>=p) update(root<<1,p,val);
    else if (mid<p) update(root<<1|1,p,val);
    pushup(root);
}

Tree query(int root,int l,int r)
{
    //cout<<root<<endl;
    if (tree[root].l==l && tree[root].r==r)
    {

        return tree[root];
    }

    int mid=(tree[root].l+tree[root].r)>>1;

    if (mid>=r)
        return query(root<<1,l,r);
    else if (mid<l)
        return query(root<<1|1,l,r);
    else
    {
        Tree tmp1=query(root<<1,l,mid);
        Tree tmp2=query(root<<1|1,mid+1,r);
        Tree tmp3;
        tmp3.ee=max(tmp1.eo+tmp2.ee,tmp1.ee+tmp2.oe);
        tmp3.ee=max(tmp3.ee,tmp1.ee);
        tmp3.ee=max(tmp3.ee,tmp2.ee);

        tmp3.oo=max(tmp1.oe+tmp2.oo,tmp1.oo+tmp2.eo);
        tmp3.oo=max(tmp3.oo,tmp1.oo);
        tmp3.oo=max(tmp3.oo,tmp2.oo);

        tmp3.eo=max(tmp1.eo+tmp2.eo,tmp1.ee+tmp2.oo);
        tmp3.eo=max(tmp3.eo,tmp1.eo);
        tmp3.eo=max(tmp3.eo,tmp2.eo);

        tmp3.oe=max(tmp1.oe+tmp2.oe,tmp1.oo+tmp2.ee);
        tmp3.oe=max(tmp3.oe,tmp1.oe);
        tmp3.oe=max(tmp3.oe,tmp2.oe);
        return tmp3;
    }

}

int main()
{
    int t,n,m;
    scanf("%d",&t);
    while (t--)
    {
        memset(tree,-inf,sizeof(tree));
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
            scanf("%I64d",&s[i]);

        build(1,1,n);

        for (int i=0;i<m;i++)
        {
            int k,a,b;
            scanf("%d",&k);
            if (k==1)
            {
                scanf("%d%d",&a,&b);
                update(1,a,b);
            }
            else
            {
                LL res=-inf;
                scanf("%d%d",&a,&b);
                Tree tmp=query(1,a,b);
                res=max(res,tmp.oo);
                res=max(res,tmp.oe);
                res=max(res,tmp.ee);
                res=max(res,tmp.eo);
                printf("%I64d\n",res);
            }
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值