题目大意
有两个长度为 nnn 的序列 aaa 和 bbb,给定 mmm 次操作,每次输入 333 个整数 op,x,yop,x,yop,x,y,对于 op=1op = 1op=1 的操作我们把 axa_xax 修改为 yyy,对于 op=2op = 2op=2 的操作我们把 bxb_xbx 修改为 yyy,对于 op=3op = 3op=3 的操作我们输出 maxx≤l≤l+1<r≤yψ(l,r)\max\limits_{x \le l \le l+1 < r \le y} \psi(l,r)x≤l≤l+1<r≤ymaxψ(l,r),其中 ψ(i,k)=ai+ak−mini<j<kbj\psi(i,k) = a_i + a_k - \min \limits _{i<j<k} b_jψ(i,k)=ai+ak−i<j<kminbj。
解决
不难看出这道题是一道线段树合并的题。线段树功能:单点修改,区间查询。
这颗线段树每个节点需要维护的信息有:
-
aaa,表示该节点及它子树中 aaa 的最大值。
-
bbb,表示该节点及它子树中 bbb 的最小值。
-
lanslanslans,表示对于该节点 iii,ai−bja_i - b_jai−bj 的最大值,其中 j>ij>ij>i。
-
ransransrans,表示对于该节点 iii,ak−bja_k - b_jak−bj 的最大值,其中 j<kj<kj<k。
-
ansansans,即答案 ψ\psiψ。
给出代码:
struct Tree
{
int a,b,lans,rans,ans;
Tree()
{
lans=rans=ans=-0x3f3f3f3f;
}
};
Tree tree[2000010];
现在开始建树。因为 aaa 和 bbb 不是一起输入的,所以先输入所有的 aaa 再 build。
给出主函数代码:
for(int i=1;i<=n;i++) read(tmp[i]);
给出 build 代码:
inline void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt].a=tmp[l],read(tree[rt].b);
return;
}
int mid=(l+r)/2;
build(ls),build(rs),pushup(rt);
}
给出 pushup 代码,因为本题只是单点修改,所以不涉及懒惰标记和 pushdown:
inline void pushup(const int &rt)
{
tree[rt].a=max(tree[rt*2].a,tree[rt*2+1].a),tree[rt].b=min(tree[rt*2].b,tree[rt*2+1].b);
tree[rt].lans=max(tree[rt*2].lans,max(tree[rt*2+1].lans,tree[rt*2].a-tree[rt*2+1].b));
tree[rt].rans=max(tree[rt*2].rans,max(tree[rt*2+1].rans,tree[rt*2+1].a-tree[rt*2].b));
tree[rt].ans=max(max(tree[rt*2].ans,tree[rt*2+1].ans),max(tree[rt*2].lans+tree[rt*2+1].a,tree[rt*2+1].rans+tree[rt*2].a));
}
这里对于第一种和第二种修改没有什么可说的,直接看查询。
查询区间为 L,RL,RL,R,查询节点区间为 l,rl,rl,r,如果查询区间完全包含了当前区间,则直接返回当前节点。
查询区间与当前节点的交集只在 l,midl,midl,mid 之间,则直接返回继续查询左儿子即可。
查询区间与当前节点的交集只在 mid+1,rmid + 1,rmid+1,r 之间,则直接返回继续查询右儿子即可。
如果在左儿子和右儿子都有,则把查询左右儿子的返回值合并再返回即可。
代码:
inline Tree ask(const int &L,const int &R,int l,int r,int rt)
{
if(l>=L && r<=R) return tree[rt];
int mid=(l+r)/2;
if(mid>=R) return ask(L,R,ls);
if(mid<L) return ask(L,R,rs);
Tree ret,x=ask(L,R,ls),y=ask(L,R,rs);
ret.a=max(x.a,y.a),ret.b=min(x.b,y.b),ret.ans=max(max(x.ans,y.ans),max(x.lans+y.a,y.rans+x.a));
ret.lans=max(x.lans,max(y.lans,x.a-y.b)),ret.rans=max(x.rans,max(y.rans,y.a-x.b));
return ret;
}
下面给出完整代码:
#include<bits/stdc++.h>
using namespace std;
#define ls l,mid,rt*2
#define rs mid+1,r,rt*2+1
#define Getchar() p1==p2 and (p2=(p1=Inf)+fread(Inf,1,1<<21,stdin),p1==p2)?EOF:*p1++
#define Putchar(c) p3==p4 and (fwrite(Ouf,1,1<<21,stdout),p3=Ouf),*p3++=c
char Inf[1<<21],Ouf[1<<21],*p1,*p2,*p3=Ouf,*p4=Ouf+(1<<21);
struct Tree
{
int a,b,lans,rans,ans;
Tree()
{
lans=rans=ans=-0x3f3f3f3f;
}
};
Tree tree[2000010];
inline void read(int &x,char c=Getchar())
{
bool f=c!='-';
x=0;
while(c<48 or c>57) c=Getchar(),f&=c!='-';
while(c>=48 and c<=57) x=(x<<3)+(x<<1)+(c^48),c=Getchar();
x=f?x:-x;
}
inline void write(int x)
{
if(x<0) Putchar('-'),x=-x;
if(x>=10) write(x/10),x%=10;
Putchar(x^48);
}
int n,m,tmp[500010];
inline void pushup(const int &rt)
{
tree[rt].a=max(tree[rt*2].a,tree[rt*2+1].a),tree[rt].b=min(tree[rt*2].b,tree[rt*2+1].b);
tree[rt].lans=max(tree[rt*2].lans,max(tree[rt*2+1].lans,tree[rt*2].a-tree[rt*2+1].b));
tree[rt].rans=max(tree[rt*2].rans,max(tree[rt*2+1].rans,tree[rt*2+1].a-tree[rt*2].b));
tree[rt].ans=max(max(tree[rt*2].ans,tree[rt*2+1].ans),max(tree[rt*2].lans+tree[rt*2+1].a,tree[rt*2+1].rans+tree[rt*2].a));
}
inline void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt].a=tmp[l],read(tree[rt].b);
return;
}
int mid=(l+r)/2;
build(ls),build(rs),pushup(rt);
}
inline void fix1(const int &pos,const int &val,int l,int r,int rt)
{
if(l==r)
{
tree[rt].a=val;
return;
}
int mid=(l+r)/2;
if(mid>=pos) fix1(pos,val,ls);
else fix1(pos,val,rs);
pushup(rt);
}
inline void fix2(const int &pos,const int &val,int l,int r,int rt)
{
if(l==r)
{
tree[rt].b=val;
return;
}
int mid=(l+r)/2;
if(mid>=pos) fix2(pos,val,ls);
else fix2(pos,val,rs);
pushup(rt);
}
inline Tree ask(const int &L,const int &R,int l,int r,int rt)
{
if(l>=L && r<=R) return tree[rt];
int mid=(l+r)/2;
if(mid>=R) return ask(L,R,ls);
if(mid<L) return ask(L,R,rs);
Tree ret,x=ask(L,R,ls),y=ask(L,R,rs);
ret.a=max(x.a,y.a),ret.b=min(x.b,y.b),ret.ans=max(max(x.ans,y.ans),max(x.lans+y.a,y.rans+x.a));
ret.lans=max(x.lans,max(y.lans,x.a-y.b)),ret.rans=max(x.rans,max(y.rans,y.a-x.b));
return ret;
}
int main()
{
read(n),read(m);
for(int i=1;i<=n;i++) read(tmp[i]);
build(1,n,1);
for(int i=1,op,x,y;i<=m;i++)
{
read(op),read(x),read(y);
if(op==1) fix1(x,y,1,n,1);
else if(op==2) fix2(x,y,1,n,1);
else write(ask(x,y,1,n,1).ans),Putchar('\n');
}
fwrite(Ouf,1,p3-Ouf,stdout),fflush(stdout);
return 0;
}

被折叠的 条评论
为什么被折叠?



