题目链接:
题意:
给定一个数组,定义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;
}