给出 2n 个数分别代表 a b 两个数组,题目要求维护数 c,c 是由 a,b 递推过来的
题目的难点在于如何将单点修改转化到区间上来,我们可以枚举一下 ci 来寻找规律
- c1=max( a1,b1 )
- c2=max( a2,max(b1+b2,a1+b2) )
- c3=max( a3,max(a2+b3,max(b1+b2+b3,a1+b2+b3) ) )
- 由此可以得出 ,其中 为 区间 [1,x] 的 b 数组的前缀和
- 所以我们将题目转化成了维护 a 数组和 b 数组上来
- 对 a 数组更新时,直接更新即可
- 对 b 数组更新时,需要更新区间 [x,n]
- 询问 c 的值时,先询问单点 x 的值,得出 的值,再询问区间 [1,x] 查询区间最大值即可
#define inf (1e18+1ll)
const int N=2e5+5;
int i,j,k;
int n,m,t;
struct Node
{
int l,r;
ll c,lazy;
void update(ll x)
{
lazy+=x;
c+=x;
}
}node[N<<2];
int a[N];
ll b[N],sum[N];
void push_up(int id)
{
node[id].c=max(node[id<<1].c,node[id<<1|1].c);
}
void push_down(int id)
{
ll x=node[id].lazy;
node[id].lazy=0;
if(x!=0){
node[id<<1].update(x);
node[id<<1|1].update(x);
}
}
void build(int l,int r,int id)
{
node[id].l=l,node[id].r=r;
node[id].lazy=0;
if(l==r) node[id].c=a[l]-sum[l];
else{
int mid=l+r>>1;
build(l,mid,id<<1);
build(mid+1,r,id<<1|1);
push_up(id);
}
}
void update(int id,int l,int r,int val)
{
int L=node[id].l,R=node[id].r;
if(L>=l && r>=R){
node[id].update(val);
} else{
int mid=L+R>>1;
push_down(id);
if(mid>=l) update(id<<1,l,r,val);
if(r>=mid+1) update(id<<1|1,l,r,val);
push_up(id);
}
}
ll query(int id,int l,int r)
{
int L=node[id].l,R=node[id].r;
if(L>=l && r>=R){
return node[id].c;
} else{
ll ans=-inf;
int mid=L+R>>1;
push_down(id);
if(mid>=l) ans=max(query(id<<1,l,r),ans);
if(r>=mid+1) ans=max(query(id<<1|1,l,r),ans);
push_up(id);
return ans;
}
}
int main()
{
//IOS;
while(~sdd(n,m)){
for(int i=1;i<=n;i++) sd(a[i]);
for(int i=1;i<=n;i++) sll(b[i]);
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+b[i];
build(1,n,1);
while(m--){
int opt=read(),x=read(),y;
if(opt==3){
ll ans=a[x]-query(1,x,x);
ll maxx=query(1,1,x);
if(maxx<0) maxx=0;
pll(ans+maxx);
} else{
y=read();
if(opt==1) update(1,x,x,y-a[x]),a[x]=y;
else update(1,x,n,b[x]-y),b[x]=y;
}
}
}
//PAUSE;
return 0;
}