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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现