hdu 5316 Magician(2015多校第三场第1题)线段树单点更新+区间合并

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

题意:给你n个点,m个操作,每次操作有3个整数t,a,b,t表示操作类型,当t=1时讲a点的值改成b;当t=0时,查询区间a,b之间最大的子序列和,这个子序列中的相邻的元素的原来的下标奇偶性都不同。

思路:这道题难点就在查询,其余都是模板,而根据查询,你只要分别把下一个区间的奇偶最大的情况分别比较,合并到上一个区间这样可以构建一个每个节点存有区间中奇开头偶开头,奇结尾,偶结尾这些区间情况的树。

代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>

#define N 100005
#define LL __int64
#define INF 0x3f3f3f3f
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct node
{
	int l,r;
	LL jo,oo,oj,jj;
}seg[N<<4],aa;
LL ans;
void Push_Up(int rt)
{
    seg[rt].jj=max(max(seg[ls].jj+seg[rs].oj,seg[ls].jo+seg[rs].jj),max(seg[ls].jj,seg[rs].jj));
    seg[rt].oo=max(max(seg[ls].oo+seg[rs].jo,seg[ls].oj+seg[rs].oo),max(seg[ls].oo,seg[rs].oo));
    seg[rt].jo=max(max(seg[ls].jj+seg[rs].oo,seg[ls].jo+seg[rs].jo),max(seg[ls].jo,seg[rs].jo));
    seg[rt].oj=max(max(seg[ls].oo+seg[rs].jj,seg[ls].oj+seg[rs].oj),max(seg[ls].oj,seg[rs].oj));
}

void Build(int l,int r,int rt)
{
    seg[rt].l=l;
    seg[rt].r=r;
    if(l==r)
    {
        LL a;
        scanf("%I64d",&a);
        if(l&1)
        {
            seg[rt].jj=a;
            seg[rt].oo=-INF;
        }
        else
        {
            seg[rt].oo=a;
            seg[rt].jj=-INF;
        }
        seg[rt].jo=seg[rt].oj=-INF;
        return ;
    }
    int m=(l+r)>>1;
    Build(lson);
    Build(rson);
    Push_Up(rt);
}

void Update(int p,int x,int rt)
{
    if(seg[rt].l==seg[rt].r&&seg[rt].l==p)
    {
        if(p&1)
            seg[rt].jj=x;
        else
            seg[rt].oo=x;
        return ;
    }
    int m=(seg[rt].l+seg[rt].r)>>1;
    if(p<=m)
        Update(p,x,ls);
    else
        Update(p,x,rs);
    Push_Up(rt);
}

void Get(node ll,node rr)
{
    aa.jj=max(max(ll.jj+rr.oj,ll.jo+rr.jj),max(ll.jj,rr.jj));
    aa.oo=max(max(ll.oo+rr.jo,ll.oj+rr.oo),max(ll.oo,rr.oo));
    aa.jo=max(max(ll.jj+rr.oo,ll.jo+rr.jo),max(ll.jo,rr.jo));
    aa.oj=max(max(ll.oo+rr.jj,ll.oj+rr.oj),max(ll.oj,rr.oj));
}

node Query(int l,int r,int rt)
{
    if(seg[rt].l==l&&seg[rt].r==r)
    {
        aa=seg[rt];
        ans=max(max(aa.jj,aa.jo),max(aa.oj,aa.oo));
        return seg[rt];
    }
    int m=(seg[rt].l+seg[rt].r)>>1;
    ans=0;
    if(r<=m)
        aa=Query(l,r,ls);
    else if(l>m)
        aa=Query(l,r,rs);
    else
    {
        node ll,rr;
        ll=Query(lson);
        rr=Query(rson);
        Get(ll,rr);
    }
    ans=max(max(aa.jj,aa.jo),max(aa.oj,aa.oo));
    return aa;
}

int main()
{
    int n,m,a,b,t,T;
	while(scanf("%d",&T)==1)
	{
	    while(T--)
        {
            scanf("%d%d",&n,&m);
            Build(1,n,1);
            while(m--)
            {
                scanf("%d%d%d",&t,&a,&b);
                if(t==1)
                    Update(a,b,1);
                else
                {
                    Query(a,b,1);
                    printf("%I64d\n",ans);
                }
            }
        }
	}
	return 0;
}


你可能感兴趣的:(线段树)