题目链接:Magician
题面:

1 1 1 1 0 1 1
1
解题:
算是比较基础的线段树吧,需要维护的值为,区间不同奇偶性起止的数列的最大值。慢慢练吧,还不是很熟练。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 1e9
#define minn -1e18
#define LL long long
using namespace std;
//节点分别存储其左边界,右边界,奇偶/偶偶/偶奇/奇奇最大值
struct node
{
int l,r;
LL OE,EE,EO,OO;
}Maxn[400010];
int p,v;
//存储原数据
LL store[100010];
LL max(LL a,LL b)
{
return a>b?a:b;
}
LL min(LL a,LL b)
{
return a<b?a:b;
}
//向上更新
void Pushup(int k)
{
//每个点的值分别为左下区间的相应最值和右下区间最值相加的最大值
Maxn[k].EO=max(minn,max(Maxn[k<<1].EO+Maxn[(k<<1)+1].EO,Maxn[k<<1].EE+Maxn[(k<<1)+1].OO));
Maxn[k].EO=max(Maxn[k].EO,Maxn[k<<1].EO);
Maxn[k].EO=max(Maxn[k].EO,Maxn[(k<<1)+1].EO);
Maxn[k].OE=max(minn,max(Maxn[k<<1].OE+Maxn[(k<<1)+1].OE,Maxn[k<<1].OO+Maxn[(k<<1)+1].EE));
Maxn[k].OE=max(Maxn[k].OE,Maxn[k<<1].OE);
Maxn[k].OE=max(Maxn[k].OE,Maxn[(k<<1)+1].OE);
Maxn[k].EE=max(minn,max(Maxn[k<<1].EO+Maxn[(k<<1)+1].EE,Maxn[k<<1].EE+Maxn[(k<<1)+1].OE));
Maxn[k].EE=max(Maxn[k].EE,Maxn[k<<1].EE);
Maxn[k].EE=max(Maxn[k].EE,Maxn[(k<<1)+1].EE);
Maxn[k].OO=max(minn,max(Maxn[k<<1].OE+Maxn[(k<<1)+1].OO,Maxn[k<<1].OO+Maxn[(k<<1)+1].EO));
Maxn[k].OO=max(Maxn[k].OO,Maxn[k<<1].OO);
Maxn[k].OO=max(Maxn[k].OO,Maxn[(k<<1)+1].OO);
}
//建树
void build(int l,int r,int k)
{
int M;
Maxn[k].l=l;
Maxn[k].r=r;
//为叶子节点
if(l==r)
{
//该位置为奇
if(l%2)
{
Maxn[k].OO=store[l];
Maxn[k].OE=Maxn[k].EE=Maxn[k].EO=minn;
}
else
{
Maxn[k].EE=store[l];
Maxn[k].OE=Maxn[k].EO=Maxn[k].OO=minn;
}
return;
}
//分别向左下区间,和右下区间建树
M=(l+r)>>1;
build(l,M,k<<1);
build(M+1,r,(k<<1)+1);
//初始化区间最值
Pushup(k);
}
//询问
node query(int l,int r,int k)
{
node temp,t1,t2;
int M;
//刚好为该区间,返回该区间最值
if (Maxn[k].l==l && Maxn[k].r==r)
return Maxn[k];
//否则取该节点对应的中点,细分
M=(Maxn[k].l+Maxn[k].r)>>1;
//完全包含在左区间
if (r<=M) return query(l,r,k<<1);
//完全包含在右区间
else if (l>M) return query(l,r,(k<<1)+1);
//落在左区间和右区间,取两边相加的最大值
else
{
t1=query(l,M,k<<1);
t2=query(M+1,r,(k<<1)+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;
}
}
//更新操作
void update(int o,int L,int R)
{
int M=L+(R-L)/2;
//叶子节点
if(L==R)
{
if(L%2)
Maxn[o].OO=v;
else
Maxn[o].EE=v;
return;
}
//继续细分
else
{
if(p<=M)
update(o*2,L,M);
else
update(o*2+1,M+1,R);
//维护区间最值
Pushup(o);
}
}
int main()
{
int t,n,m,a,oper;
scanf("%d",&t);
while(t--)
{
//读入
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&store[i]);
build(1,n,1);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&oper,&a,&v);
//查询操作
if(oper==0)
{
node temp=query(a,v,1);
LL ans=minn;
ans=max(ans,temp.OO);
ans=max(ans,temp.OE);
ans=max(ans,temp.EE);
ans=max(ans,temp.EO);
printf("%lld\n",ans);
}
//更新操作,v设置为全局了
else
{
p=a;
update(1,1,n);
}
}
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 5316 Magician (线段树区间最值,单点更新)
原文地址:http://blog.csdn.net/david_jett/article/details/47185799