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

1 1 1 1 0 1 1
1
题意:
给出 n 个点和 m 个操作;
1:1 a b 将 a 点的值改成 b
2: 0 a b 查询子区间 a 到 b 之间最大的子序列和(这个子序列(可以不连续)中的相邻的元素的原来的下标奇偶性都不同)
PS:
官方题解:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
//lson和rson分辨表示结点的左儿子和右儿子
//rt表示当前子树的根(root),也就是当前所在的结点
const int maxn = 100000+7;
struct node
{
int has[2][2];//是否有这种情况
LL val[2][2];//该情况的最大值
} tre[maxn<<2];
int max(int x,int y)
{
if(x > y)
return x;
return y;
}
//合并
node UNION(node a,node b)
{
node c;
//四种起始和终止情况可以直接继承于左儿子或右儿子的对应情况
for(int i = 0; i <= 1; i++)
{
for(int j = 0; j <= 1; j++)
{
c.has[i][j] = a.has[i][j] + b.has[i][j];
if(a.has[i][j] && b.has[i][j])
c.val[i][j] = max(a.val[i][j], b.val[i][j]);
else if(a.has[i][j])
c.val[i][j] = a.val[i][j];
else if(b.has[i][j])
c.val[i][j] = b.val[i][j];
}
}
//四种情况由左儿子和右儿子的情况合并。
//如奇始奇终可以由左儿子的奇始奇终和右儿子的偶始奇终合并
//也可以由左儿子的奇始偶终和右儿子的奇始奇终合并,,以此类推
for(int i = 0; i <= 1; i++)
{
for(int j = 0; j <= 1; j++)
{
for(int k = 0; k <= 1; k++)
{
if(a.has[i][j] && b.has[!j][k])
{
if(c.has[i][k])
{
c.val[i][k] = max(c.val[i][k], a.val[i][j]+b.val[!j][k]);
}
else
{
c.has[i][k] = 1;
c.val[i][k]=a.val[i][j]+b.val[!j][k];
}
}
}
}
}
return c;
}
void PushUP(int rt)
{
tre[rt] = UNION(tre[rt<<1],tre[rt<<1|1]);
}
void build(int l,int r,int rt)
{
memset(tre[rt].has,0,sizeof(tre[rt].has));
if (l == r)
{
int tt;
scanf("%d",&tt);
tre[rt].has[l%2][l%2] = 1;
tre[rt].val[l%2][l%2] = tt;
return ;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
PushUP(rt);
}
void update(int p,int sc,int l,int r,int rt)
{
if (l == r) //叶节点
{
memset(tre[rt].has,0,sizeof(tre[rt].has));
tre[rt].has[l%2][l%2] = 1;
tre[rt].val[l%2][l%2] = sc;
return ;
}
int mid = (l + r) >> 1;
if (p <= mid)//递归更新左子树或者右子树
update(p , sc , lson);
else
update(p , sc , rson);
PushUP(rt);
}
node query(int L,int R,int l,int r,int rt)
{
if (L <= l && r <= R)
{
return tre[rt];
}
int flag1 = 0, flag2 = 0;
node ans1, ans2;
int mid = (l + r) >> 1;
if (L <= mid) //往左走
{
ans1 = query(L , R , lson);
flag1 = 1;
}
if (mid < R)//往右走
{
ans2 = query(L , R , rson);
flag2 = 1;
}
if(!flag1)
{
return ans2;
}
if(!flag2)
{
return ans1;
}
return UNION(ans1,ans2);
}
int main()
{
int t;
int N , M;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&N,&M);
build(1 , N , 1); //建树
while(M--)
{
int op, a , b;
scanf("%d%d%d",&op,&a,&b);
if(op == 1)
{
update(a , b , 1 , N , 1);
}
else if (op == 0)
{
node t = query(a , b , 1 , N , 1);
LL ans;
int flag = 0;
for(int i = 0; i <= 1; i++)
{
for(int j = 0; j <= 1; j++)
{
if(t.has[i][j])
{
if(flag == 0)
{
ans = t.val[i][j];
flag=1;
}
else
ans = max(ans, t.val[i][j]);
}
}
}
printf("%lld\n",ans);
}
}
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 5316 Magician(线段树区间合并, 子序列最值 多校2015啊)
原文地址:http://blog.csdn.net/u012860063/article/details/47134499