HDU 5316 线段树区间最值问题

T组数据

N个数字,M次操作

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

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

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

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

ee:以偶数下标开始偶数下标结束的最大和

eo:以偶数下标开始奇数下标结束的最大和

oe:以奇数下标开始偶数下标结束的最大和

oo:以奇数下标开始奇数下标结束的最大和

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

修改时单点更新即可

#include "stdio.h"
#include "string.h"
const __int64 inf=0x3f3f3f3f3f3f3f3f;
__int64 ans,a[100100];

struct node
{
    int l,r;
    __int64 ee,eo,oe,oo;
}data[400010];

__int64 Max(__int64 a,__int64 b)
{
    if (a<b) return b;else return a;
}

void Pushup(int k)
{
    data[k].ee=Max(-inf,Max(data[k*2].ee+data[k*2+1].oe,data[k*2].eo+data[k*2+1].ee));
    data[k].ee=Max(data[k].ee,data[k*2].ee);
    data[k].ee=Max(data[k].ee,data[k*2+1].ee);

    data[k].oo=Max(-inf,Max(data[k*2].oo+data[k*2+1].eo,data[k*2].oe+data[k*2+1].oo));
    data[k].oo=Max(data[k].oo,data[k*2].oo);
    data[k].oo=Max(data[k].oo,data[k*2+1].oo);

    data[k].eo=Max(-inf,Max(data[k*2].ee+data[k*2+1].oo,data[k*2].eo+data[k*2+1].eo));
    data[k].eo=Max(data[k].eo,data[k*2].eo);
    data[k].eo=Max(data[k].eo,data[k*2+1].eo);

    data[k].oe=Max(-inf,Max(data[k*2].oo+data[k*2+1].ee,data[k*2].oe+data[k*2+1].oe));
    data[k].oe=Max(data[k].oe,data[k*2].oe);
    data[k].oe=Max(data[k].oe,data[k*2+1].oe);
}

void build(int l,int r,int k)
{
    int mid;
    data[k].l=l;
    data[k].r=r;
    if (l==r)
    {
        if (l%2==1)
        {
            data[k].oo=a[l];
            data[k].oe=data[k].eo=data[k].ee=-inf;
        }
        else
        {
            data[k].ee=a[l];
            data[k].oe=data[k].eo=data[k].oo=-inf;
        }
        return ;
    }

    mid=(l+r)/2;

    build(l,mid,k*2);
    build(mid+1,r,k*2+1);

    Pushup(k);
}

void updata(int n,int x,int k)
{
    if (data[k].l==n && data[k].r==n)
    {
        if (data[k].l%2==1)
        {
            data[k].oo=x;
            data[k].eo=data[k].oe=data[k].ee=-inf;
        }
        else
        {
            data[k].ee=x;
            data[k].eo=data[k].oe=data[k].oo=-inf;
        }
        return ;
    }

    if (n<=data[k*2].r) updata(n,x,k*2);
    else updata(n,x,k*2+1);

    Pushup(k);
}

node search(int l,int r,int k)
{
    node temp,t1,t2;
    int mid;
    if (data[k].l==l && data[k].r==r)
    {
        temp.ee=data[k].ee;
        temp.oo=data[k].oo;
        temp.eo=data[k].eo;
        temp.oe=data[k].oe;
        return temp;
    }

    mid=(data[k].l+data[k].r)/2;
    if (r<=mid) return search(l,r,k*2);
    else
        if (l>mid) return search(l,r,k*2+1);
    else
    {
        t1=search(l,mid,k*2);
        t2=search(mid+1,r,k*2+1);
        temp.ee=Max(Max(Max(t1.ee+t2.oe,t1.eo+t2.ee),t1.ee),t2.ee);
        temp.eo=Max(Max(Max(t1.eo+t2.eo,t1.ee+t2.oo),t1.eo),t2.eo);
        temp.oo=Max(Max(Max(t1.oo+t2.eo,t1.oe+t2.oo),t1.oo),t2.oo);
        temp.oe=Max(Max(Max(t1.oo+t2.ee,t1.oe+t2.oe),t1.oe),t2.oe);
        return temp;
    }
}

int main()
{
    int t,n,m,i,op,l,r;
    node mark;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        for (i=1;i<=n;i++)
            scanf("%I64d",&a[i]);
        build(1,n,1);
        while (m--)
        {
            scanf("%d%d%d",&op,&l,&r);
            if (op==0)
            {
                ans=-inf;
                mark=search(l,r,1);
                ans=Max(ans,mark.oo);
                ans=Max(ans,mark.ee);
                ans=Max(ans,mark.eo);
                ans=Max(ans,mark.oe);

                printf("%I64d\n",ans);
            }
            else
                updata(l,r,1);
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-10 03:41:44

HDU 5316 线段树区间最值问题的相关文章

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i

HDU 4339 线段树区间合并

Query Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2573    Accepted Submission(s): 851 Problem Description You are given two strings s1[0..l1], s2[0..l2] and Q - number of queries.Your task

【POJ】3264 Balanced Lineup ——线段树 区间最值

Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 34140   Accepted: 16044 Case Time Limit: 2000MS Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer Joh

HDU 4578 线段树区间更新(确定区间操作的优先级)

HDU 4578 线段树区间更新 操作有: 区间所有数add(c) 区间所有数mul(c) 区间所有数set(c) 查询有: 区间所有数的p次方和(p>= 1 && p <= 3) 关键是区间更新的三种操作的优先级的确定清楚set>mul>add 关键是:down和update中对区间的更新操作是一回事,可以写成函数方便编程 //#pragma warning (disable: 4786) //#pragma comment (linker, "/STA

【hdu5306】Gorgeous Sequence 线段树区间最值操作

题目描述 给你一个序列,支持三种操作: $0\ x\ y\ t$ :将 $[x,y]$ 内大于 $t$ 的数变为 $t$ :$1\ x\ y$ :求 $[x,y]$ 内所有数的最大值:$2\ x\ y$ :求 $[x,y]$ 内所有数的和. 多组测试数据,$\sum n,\sum m\le 10^6$ 题解 线段树区间最值操作 对于线段树上的一个节点,维护对应区间的:最大值 $mx$ .最大值个数 $c$ 及严格次大值 $se$ .那么对于一次区间最小值操作: 如果 $t\ge mx$ ,则这个

hdu 3308(线段树区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6069    Accepted Submission(s): 2635 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

HDU 3911 线段树区间合并

北京赛区快了,准备袭击数据结构和图论.倒计时 18天,线段树区间合并.维护一个最长连续.. 题意:给一个01串,以下有一些操作,问区间最长的连续的1的个数 思路:非常裸的线段树区间合并 #include<iostream> #include<cstdio> #include<map> #include<set> #include<cmath> #define lson id << 1 #define rson id <<

HDU 5316 Magician (线段树区间最值,单点更新)

题目链接:Magician 题面: Magician Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1911    Accepted Submission(s): 549 Problem Description Fantasy magicians usually gain their ability through one of t

HDU 1754(线段树区间最值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 48513    Accepted Submission(s): 18986 Problem Description 非常多学校流行一种比較的习惯.老师们非常喜欢询问.从某某到某某其中,分数最高的是多少. 这让非常多学生非常反感. 无论你喜不喜欢,如今须要你做的是,就是