hdu5316区间最值问题(附带题目意思详解) 一次ac

T组数据

N个数字,M次操作

op=0:找出L-R区间内的最大‘值’

op=1:把a位置的数字换成b

对最大‘值’的定义:取区间内的最大子序列,需要保证子序列的下标为奇偶交替的


用线段树分别记录每个区间的

.........s1.......奇数位开始,奇数位结束
.........s2.......奇数位开始,偶数为结束
.........s3.......偶数位开始,偶数位结束
.........s4.......偶数位开始,奇数位结束


对每次询问分别处理4种情况的最大值即可

此题乍一看比较麻烦, 笔者刚开始想到dp,但没有思路,而此题又有很裸地线段树特点,于是用线段树做。此题与一般线段树不同的是,节点上记录的是几个值

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=100010;
const ll INF=-1e9;
int n,m;
ll t,a[N];
typedef struct
{
    int left,right;
//.........s1.......奇数位开始,奇数位结束
//.........s2.......奇数位开始,偶数为结束
//.........s3.......偶数位开始,偶数位结束
//.........s4.......偶数位开始,奇数位结束
    ll s1,s2,s3,s4;
}P;
P per[4*N];
typedef struct
{
    ll s1,s2,s3,s4;
}data;
ll MAX(ll a,int b)
{
    if(a>b)
        return a;
    return b;
}
ll MAX(ll a,ll b,ll c,ll d)
{
    ll m1=max(a,b),m2=max(c,d);
    return max(m1,m2);
}
void build(int id,ll left,ll right)
{
    per[id].left=left;
    per[id].right=right;
    if(left==right)
    {
        if(left&1)
        {
            per[id].s1=a[left];
            per[id].s2=INF;
            per[id].s3=INF;
            per[id].s4=INF;
        }
        else
        {
            per[id].s1=INF;
            per[id].s2=INF;
            per[id].s3=a[left];
            per[id].s4=INF;
        }
        return;
    }
    else
    {
        int mid=(left+right)>>1,len1=id<<1,len2=id<<1|1;
        build(len1,left,mid);
        build(len2,mid+1,right);
        ll as1,as2,as3,as4,bs1,bs2,bs3,bs4;
        as1=per[len1].s1;   as2=per[len1].s2;
        as3=per[len1].s3;   as4=per[len1].s4;
        bs1=per[len2].s1;   bs2=per[len2].s2;
        bs3=per[len2].s3;   bs4=per[len2].s4;
        per[id].s1=MAX(as1,bs1,as1+bs4,as2+bs1);
        per[id].s2=MAX(as2,bs2,as2+bs2,as1+bs3);
        per[id].s3=MAX(as3,bs3,as3+bs2,as4+bs3);
        per[id].s4=MAX(as4,bs4,as4+bs4,as3+bs1);
    }


}
void update(int id,ll a,ll b)
{//cout<<"a= "<<a<<" b= "<<b<<endl;
    if(per[id].left>a||per[id].right<a)
        return;
    if(per[id].left==per[id].right&&per[id].left==a)
    {//cout<<"updata= "<<a<<" b= "<<b<<endl;
        if(a&1)
            per[id].s1=b;
        else
            per[id].s3=b;
    }
    else
    {
        ll mid=(per[id].left+per[id].right)>>1;
        ll len1=id<<1,len2=len1+1;
        if(mid<a)
            update(len2,a,b);
        else
            if(mid>=a)
            update(len1,a,b);
            ll as1,as2,as3,as4,bs1,bs2,bs3,bs4;
        as1=per[len1].s1;   as2=per[len1].s2;
        as3=per[len1].s3;   as4=per[len1].s4;
        bs1=per[len2].s1;   bs2=per[len2].s2;
        bs3=per[len2].s3;   bs4=per[len2].s4;
        per[id].s1=MAX(as1,bs1,as1+bs4,as2+bs1);
        per[id].s2=MAX(as2,bs2,as2+bs2,as1+bs3);
        per[id].s3=MAX(as3,bs3,as3+bs2,as4+bs3);
        per[id].s4=MAX(as4,bs4,as4+bs4,as3+bs1);
    }
}
data query(int id,ll l,ll r)
{
    ll s;
    if(per[id].left==l&&per[id].right==r)
    {
        data da;
        da.s1=per[id].s1;   da.s2=per[id].s2;
        da.s3=per[id].s3;   da.s4=per[id].s4;
        return da;
    }
    if(per[id].left>r||per[id].right<l)
    {
        data da;
        da.s1=INF;   da.s2=INF;
        da.s3=INF;   da.s4=INF;
        return da;
    }
    ll mid=(per[id].left+per[id].right)>>1;
    ll len1=id<<1,len2=len1+1;
    if(r<=mid)
        return query(len1,l,r);
    else
        if(l>mid)
            return query(len2,l,r);
    else
        {
            data d1=query(len1,l,mid);
            data d2=query(len2,mid+1,r);
            data d3;
            d3.s1=MAX(d1.s1,d2.s1,d1.s1+d2.s4,d1.s2+d2.s1);
            d3.s2=MAX(d1.s2,d2.s2,d1.s1+d2.s3,d1.s2+d2.s2);
            d3.s3=MAX(d1.s3,d2.s3,d1.s3+d2.s2,d1.s4+d2.s3);
            d3.s4=MAX(d1.s4,d2.s4,d1.s3+d2.s1,d1.s4+d2.s4);
            return d3;
        }
}
int main()
{
    int i,j;
    ll l,r,k;
    while(~scanf("%d",&t))
    {
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(i=1;i<=n;i++)
                scanf("%lld",&a[i]);
            build(1,1,n);
            for(i=0;i<m;i++)
            {
                cin>>k>>l>>r;
                if(k==0)
                {
                    data da=query(1,l,r);
                    ll mmax=MAX(da.s1,da.s2,da.s3,da.s4);
                    cout<<mmax<<endl;
                }
                if(k==1)
                {
                    update(1,l,r);
                    //for(i=1;i<=4*n;i++)
                }
            }
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值