#Snow{ position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 99999; background: rgba(255,255,240,0.1); pointer-events: none; }

2022CSP二轮T2

感觉今年T2思维难度不是很大(因为我只会这个题),就是线段树维护最大值最小值的问题,只要认真想,是完全可以驾驭的。

我说说我考场上的思路:

因为是区间上的问题,第一眼看上去还和最大值最小值有关,所以想到线段树

维护六个值:

a中最大值(maxa)

a中最小值(mina)

a中大于等于0的数中最小的(minz)>>(min正)

a中小于等于0的数中最大的(maxf)>>(max负)

b中最大值(maxb)

b中最小值(minb)

注意:因为选择时A先选,所以A具有主动权!!

分以下几种情况:

(因为不想单独考虑0,所以我都是用的非负数,非正数这些)

1.当b区间只有小于等于0的数时,考虑a区间,如果mina小于等于0,那肯定A优先选mina,B选maxb;如果a区间最小值大于等于0,那肯定A还是优先选mina,但此时B选minb

2.当b区间只有大于等于0的数时,考虑a区间,如果maxa大于等于0,那肯定A优先选maxa,B选minb;如果a区间最大值小于等于0,那肯定A还是优先选maxa,但此时B选maxb

3.若b区间有正数也有负数,还需要考虑a区间

	1.如果a区间只有小于等于0的数,则是maxf * maxb
	2.如果a区间只有大于等于0的数,则是minz * minb
	3.如果a区间有大于等于0的数也有小于等于0的数,则取max(maxf * maxb,minz * minb)
	为什么取max?因为A有优先权,A一定会使结果最大,所以取大

附上代码

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+10;
int n,m,q;
int a[N],b[N];

struct T1
{
	int l,r;
	int maxa,mina,maxf,minz;
}t1[N<<2];

struct T2
{
	int l,r;
	int maxb,minb;
}t2[N<<2];

T1 update1(T1 &p,T1 ls,T1 rs)
{
	p.maxa=max(ls.maxa,rs.maxa);
	p.mina=min(ls.mina,rs.mina);
	if(ls.minz==2e9&&rs.minz!=2e9)p.minz=rs.minz;
	if(ls.minz!=2e9&&rs.minz==2e9)p.minz=ls.minz;
	if(ls.minz!=2e9&&rs.minz!=2e9)p.minz=min(ls.minz,rs.minz);
	if(ls.minz==2e9&&rs.minz==2e9)p.minz=2e9;
	if(ls.maxf==2e9&&rs.maxf!=2e9)p.maxf=rs.maxf;
	if(ls.maxf!=2e9&&rs.maxf==2e9)p.maxf=ls.maxf;
	if(ls.maxf!=2e9&&rs.maxf!=2e9)p.maxf=max(ls.maxf,rs.maxf);
	if(ls.maxf==2e9&&rs.maxf==2e9)p.maxf=2e9;
	return p;
}

void build1(int p,int l,int r)
{
	t1[p].l=l;
	t1[p].r=r;
	if(l==r)
	{
		t1[p].maxa=a[l];
		t1[p].mina=a[l];
		if(a[l]<0)
		{
			t1[p].minz=2e9;
			t1[p].maxf=a[l];
		}
		if(a[l]>0)
		{
			t1[p].minz=a[l];
			t1[p].maxf=2e9;
		}
		if(a[l]==0)t1[p].minz=t1[p].maxf=0;
		return;
	}
	int mid=l+r>>1;
	build1(p<<1,l,mid);
	build1(p<<1|1,mid+1,r);
	update1(t1[p],t1[p<<1],t1[p<<1|1]);
}

T1 ask1(int p,int l,int r)
{
	if(l<=t1[p].l&&r>=t1[p].r)return t1[p];
	T1 ans;
	int mid=(t1[p].l+t1[p].r)>>1;
	if(l<=mid&&r>mid)return update1(ans,ask1(p<<1,l,r),ask1(p<<1|1,l,r));
	if(r<=mid)return ask1(p<<1,l,r);
	if(l>mid)return ask1(p<<1|1,l,r);
}

T2 update2(T2 &p,T2 ls,T2 rs)
{
	p.maxb=max(ls.maxb,rs.maxb);
	p.minb=min(ls.minb,rs.minb);
	return p;
}

void build2(int p,int l,int r)
{
	t2[p].l=l;
	t2[p].r=r;
	if(l==r)
	{
		t2[p].maxb=b[l];
		t2[p].minb=b[l];
		return;
	}
	int mid=l+r>>1;
	build2(p<<1,l,mid);
	build2(p<<1|1,mid+1,r);
	update2(t2[p],t2[p<<1],t2[p<<1|1]);
}

T2 ask2(int p,int l,int r)
{
	if(l<=t2[p].l&&r>=t2[p].r)return t2[p];
	T2 ans;
	int mid=(t2[p].l+t2[p].r)>>1;
	if(l<=mid&&r>mid)return update2(ans,ask2(p<<1,l,r),ask2(p<<1|1,l,r));
	if(r<=mid)return ask2(p<<1,l,r);
	if(l>mid)return ask2(p<<1|1,l,r);
}

int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)scanf("%d",&b[i]);
	build1(1,1,n);
	build2(1,1,m);
	while(q--)
	{
		int l1,r1,l2,r2;
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		T1 ans1=ask1(1,l1,r1);
		T2 ans2=ask2(1,l2,r2);
		if(ans2.maxb<=0)
		{
			if(ans1.mina<=0)cout<<1ll*ans1.mina*ans2.maxb<<"\n";
			else cout<<1ll*ans1.mina*ans2.minb<<"\n";
			continue;
		}
		if(ans2.minb>=0)
		{
			if(ans1.maxa>=0)cout<<1ll*ans1.maxa*ans2.minb<<"\n";
			else cout<<1ll*ans1.maxa*ans2.maxb<<"\n";
			continue;
		}
		if(ans2.maxb>0&&ans2.minb<0)
		{
			if(ans1.minz==2e9&&ans1.maxf!=2e9)
			{
				cout<<1ll*ans1.maxf*ans2.maxb<<"\n";
				continue;
			}
			if(ans1.minz!=2e9&&ans1.maxf==2e9)
			{
				cout<<1ll*ans1.minz*ans2.minb<<"\n";
				continue;
			}
			if(ans1.minz!=2e9&&ans1.maxf!=2e9)
			{
				cout<<1ll*max(1ll*ans1.maxf*ans2.maxb,1ll*ans1.minz*ans2.minb)<<"\n";
				continue;
			}
		}
	}
	return 0;
}
posted @   Eternal-QX  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示