求求调调,对拍很久也没错交上去0分。。
查看原帖
求求调调,对拍很久也没错交上去0分。。
65190
_LanFeng_楼主2021/9/11 09:34

RT,具体思路跟题解一样,查询的时候有点变化。具体看代码注释。谢谢各位神仙

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const ll INF=1e14;
const int N=5e5+10;
int n,m;
ll maxa,maxsuf;
int tp;
ll st[N];
struct
{
	int l,r;
	ll maxa,minb,phi,pre,suf;//pre表示这个节点所代表的区间的最大的a-b,其中a在b后面
     //同理suf代表a在b前面的最大的值
     //phi表示这个区间的答案
}t[N<<3];
ll a[N],b[N];
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-48;s=getchar();}
    return x*f;
}
void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r)
	{
		t[p].maxa=a[l];
		t[p].minb=b[l];
		t[p].suf=t[p].phi=t[p].pre=-INF;
		return;
	}
	int mid=l+r>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	t[p].maxa=max(t[p<<1].maxa,t[p<<1|1].maxa);
	t[p].minb=min(t[p<<1].minb,t[p<<1|1].minb);
	t[p].pre=max(t[p<<1|1].maxa-t[p<<1].minb,max(t[p<<1].pre,t[p<<1|1].pre));
	t[p].suf=max(t[p<<1].maxa-t[p<<1|1].minb,max(t[p<<1].suf,t[p<<1|1].suf))
	t[p].phi=max(t[p<<1].suf+t[p<<1|1].maxa,max(t[p<<1|1].pre+t[p<<1].maxa,max(t[p<<1].phi,t[p<<1|1].phi)));
}
ll ask(int p,int l,int r)//这个函数查询每个区间的最大答案值
{
	if(t[p].l>r||t[p].r<l) return -INF;
	if(t[p].l>=l&&t[p].r<=r) return t[p].phi;
	return max(ask(p<<1,l,r),ask(p<<1|1,l,r));
}
ll ask1(int p,int l,int r)//这个函数假设需要知道一个区间的pre,另一个a(即三元组的最开始的a在前面已经查询过的区间),然后更新最大值;而同时讨论suf的情况
{
	if(t[p].l>r||t[p].r<l) return -INF;
	if(t[p].l>=l&&t[p].r<=r) 
	{
		ll Max=max(t[p].pre+maxa,maxsuf+t[p].maxa);
		maxa=max(maxa,t[p].maxa);
		maxsuf=max(maxsuf,t[p].suf);
		return Max;
	}
	ll Max=ask1(p<<1,l,r);
	Max=max(Max,ask1(p<<1|1,l,r));
	return Max;
}
ll ask2(int p,int l,int r)//这个函数表示三元组的每一个元素都不在同一个区间,我们需要知道当前节点的minb,前面所查询过得区间的最大值a,以及后面还没有查询的区间的最大值a,用三者更新答案
{
	if(t[p].l>r||t[p].r<l) return -INF;
	if(t[p].l>=l&&t[p].r<=r) 
	{
		tp--;
		ll Max=maxa+st[tp]-t[p].minb;
		maxa=max(maxa,t[p].maxa);
		return Max;
	}
	ll Max=ask2(p<<1,l,r);
	Max=max(Max,ask2(p<<1|1,l,r));
	return Max;
}
void search(int p,int l,int r)//这个函数用来维护当前询问后面未走过的区间的最大值a,类似于“对顶堆”
{
	if(t[p].l>r||t[p].r<l) return;
	if(t[p].l>=l&&t[p].r<=r) 
	{
		st[++tp]=max(t[p].maxa,st[tp-1]);
		return;
	}
	search(p<<1|1,l,r);
	search(p<<1,l,r);
}
void modify(int p,int x,ll y,int op)
{
	if(t[p].l>x||t[p].r<x) return;
	if(t[p].l==t[p].r)
	{
		if(op==1) t[p].maxa=y;
		else t[p].minb=y;
		return;
	}
	modify(p<<1,x,y,op);
	modify(p<<1|1,x,y,op);
	t[p].maxa=max(t[p<<1].maxa,t[p<<1|1].maxa);
	t[p].minb=min(t[p<<1].minb,t[p<<1|1].minb);
	t[p].pre=max(t[p<<1|1].maxa-t[p<<1].minb,max(t[p<<1].pre,t[p<<1|1].pre));
	t[p].suf=max(t[p<<1].maxa-t[p<<1|1].minb,max(t[p<<1].suf,t[p<<1|1].suf));
	t[p].phi=max(t[p<<1].suf+t[p<<1|1].maxa,max(t[p<<1|1].pre+t[p<<1].maxa,max(t[p<<1].phi,t[p<<1|1].phi)));
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	a[i]=read();
	for(int i=1;i<=n;i++)
	b[i]=read();
	build(1,1,n);
	st[0]=-INF;
	for(int i=1,op,x,y;i<=m;i++)
	{
		op=read(),x=read(),y=read();
		if(op==3) 
		{
			tp=0;
			search(1,x,y);
			maxa=maxsuf=-INF;
			ll ans=max(ask(1,x,y),ask1(1,x,y));
			maxa=-INF;
			ans=max(ans,ask2(1,x,y));
			printf("%lld\n",ans);
		}
		else modify(1,x,(ll)y,op);
	} 
	return 0;
}
2021/9/11 09:34
加载中...