题意:
给你n个女生和m个男生的值,如果第i个女生的值和第j个男生的值相加>=k,他们就可以在一起,现在有q次询问,每次问你l-r的区间内的男生能否将所有女生拿下。
题解:
这题我想了很久啊,到结束过10分钟才想出来,但是有点复杂,就不敲了。看了别人的代码感觉和我差不多,但是方法比我简单,很优秀,推崇。
首先将所有a变成k-a,为什么,因为直接比较大小一般比相加再比较大小来的方便。然后将所有a排个序,这时候build线段树:最左边设为-n-1,第二个设为-n,最右边设为-1.为什么要这么设?因为右边的数比左边的大,所以当一个男生的值比较大的时候,就可以替代比较小的值的要求。当mi[1]>=0的时候就代表所有女生都找到了男生。之后就是枚举左端点找每个左端点至少的右端点在哪才能将所有女生匹配,这时候就用类似尺取的方法即可。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int mi[N*4],flag[N*4],a[N],b[N],rig[N];
void push_down(int root)
{
if(!flag[root])
return ;
mi[root<<1]+=flag[root];
mi[root<<1|1]+=flag[root];
flag[root<<1]+=flag[root];
flag[root<<1|1]+=flag[root];
flag[root]=0;
}
void build(int l,int r,int root,int n)
{
if(l==r)
{
mi[root]=l-n-1;
flag[root]=0;
return ;
}
int mid=l+r>>1;
build(l,mid,root<<1,n);
build(mid+1,r,root<<1|1,n);
mi[root]=min(mi[root<<1],mi[root<<1|1]);
}
void update(int l,int r,int root,int ql,int qr,int val)
{
if(l>=ql&&r<=qr)
{
mi[root]+=val;
flag[root]+=val;
return ;
}
push_down(root);
int mid=l+r>>1;
if(mid>=ql)
update(l,mid,root<<1,ql,qr,val);
if(mid<qr)
update(mid+1,r,root<<1|1,ql,qr,val);
mi[root]=min(mi[root<<1],mi[root<<1|1]);
}
int query(int l,int r,int root,int ql,int qr)
{
if(l>=ql&&r<=qr)
return mi[root];
push_down(root);
int ans=1e9;
int mid=l+r>>1;
if(mid>=ql)
ans=min(ans,query(l,mid,root<<1,ql,qr));
if(mid<qr)
ans=min(ans,query(mid+1,r,root<<1|1,ql,qr));
return ans;
}
int main()
{
int t;
while(~scanf("%d",&t))
{
while(t--)
{
int n,m,k,q;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]=k-a[i];
sort(a+1,a+1+n);
build(1,n,1,n);
for(int i=1;i<=m;i++)
scanf("%d",&b[i]);
int l=1,r=0;
while(l<=m)
{
if(r<l)
{
int p=upper_bound(a+1,a+1+n,b[++r])-a-1;
if(p)
update(1,n,1,1,p,1);
}
while(mi[1]<0&&r<m)
{
int p=upper_bound(a+1,a+1+n,b[++r])-a-1;
if(p)
update(1,n,1,1,p,1);
}
if(mi[1]<0)
rig[l]=1e9;
else
rig[l]=r;
int p=upper_bound(a+1,a+1+n,b[l++])-a-1;
if(p)
update(1,n,1,1,p,-1);
}
scanf("%d",&q);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",rig[l]<=r);
}
}
}
return 0;
}