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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luyehao1/article/details/83038341

题目链接:

Magician

题意:

给定一个数组,定义beautiful subsequence为一个序列,里面每个元素在给定数组中的下标是奇偶交替的。

有2种操作:

0 求区间[a,b]中满足beautiful subsequence的序列中,序列所有元素之和的最大值。

1 把原数组中下标为a的那个元素的值改为b。

思路:

线段树单点更新+区间合并

一个区间内的beautiful subsequence只有4种情况,奇开头奇结尾、奇开头偶结尾、偶开头奇结尾和偶开头偶结尾。因此,对于每段区间,我们只要保存这4种情况的最大值,就可以根据此进行区间合并,比如奇结尾的只能跟偶开头的合并。最后,取这4种情况中的最大值即可。

code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int MAX = 100000 + 100;
const ll inf = 1e18;

typedef struct{
    ll ex[3][3];
    ll val[3][3];
}Point;

ll n,m;
Point tree[MAX<<2];

//区间合并
Point pushup(Point a,Point b)
{
    Point c;
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            c.ex[i][j]=a.ex[i][j]|b.ex[i][j];
            if(a.ex[i][j]&&b.ex[i][j])
                c.val[i][j]=max(a.val[i][j],b.val[i][j]);
            else if(a.ex[i][j])
                c.val[i][j]=a.val[i][j];
            else if(b.ex[i][j])
                c.val[i][j]=b.val[i][j];
        }
    }
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            for(int k=0;k<2;k++){
                if(a.ex[i][j]&&b.ex[!j][k]){
                    if(c.ex[i][k])
                        c.val[i][k]=max(c.val[i][k],a.val[i][j]+b.val[!j][k]);
                    else{
                        c.ex[i][k]=1;
                        c.val[i][k]=a.val[i][j]+b.val[!j][k];
                    }
                }
            }
        }
    }
    return c;
}

//线段树模版
void build(int l,int r,int root)
{
    memset(tree[root].ex,0,sizeof(tree[root].ex));
    if(l==r){
        ll x;
        scanf("%lld",&x);
        tree[root].ex[l%2][l%2]=1;
        tree[root].val[l%2][l%2]=x;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    tree[root]=pushup(tree[root<<1],tree[root<<1|1]);
}

void update(int L,ll C,int l,int r,int root)
{
    if(l==r){
        memset(tree[root].ex,0,sizeof(tree[root].ex));
        tree[root].ex[L%2][L%2]=1;
        tree[root].val[L%2][L%2]=C;
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid)  update(L,C,l,mid,root<<1);
    else update(L,C,mid+1,r,root<<1|1);
    tree[root]=pushup(tree[root<<1],tree[root<<1|1]);
    return;
}

Point query(int L,int R,int l,int r,int root)
{
    if(L<=l&&r<=R){
        return tree[root];
    }
    int mid=(l+r)>>1;
    Point ans1,ans2;
    int fg1=0,fg2=0;
    if(L<=mid){
        ans1=query(L,R,l,mid,root<<1);
        fg1=1;
    }
    if(R>mid){
        ans2=query(L,R,mid+1,r,root<<1|1);
        fg2=1;
    }
    if(fg1==0)  return ans2;
    else if(fg2==0) return ans1;
    else    return pushup(ans1,ans2);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        build(1,n,1);
        while(m--){
            ll op,x,y;
            scanf("%lld%lld%lld",&op,&x,&y);
            if(op==0){
                Point ans=query(x,y,1,n,1);
                ll Max;
                int fg=0;
                //ans为4中情况的最大值
                for(int i=0;i<2;i++){
                    for(int j=0;j<2;j++){
                        if(ans.ex[i][j]){
                            if(fg==0){
                                Max=ans.val[i][j];
                                fg=1;
                            }
                            else
                                Max=max(Max,ans.val[i][j]);
                        }
                    }
                }
                printf("%lld\n",Max);
            }
            else if(op==1){
                update(x,y,1,n,1);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/luyehao1/article/details/83038341
今日推荐