Wrapping Chocolate(ABC 245 E)
题目大意
有\(N\)块巧克力,第\(i\)块的宽度为\(A_i\),长度为\(B_i\),同时还有\(M\)个放巧克力的盒子,第\(i\)个盒子的宽度为\(C_i\),长度为\(D_i\),定义第\(i\)块巧克力能被放进第\(j\)个盒子中当且仅当\(A_i\le C_i\&\&B_i\le D_i\),每个盒子中只能放入一块巧克力,问这\(N\)块巧克力能不能都被放进盒子中。\((1\le N\le M\le2\times10^5,1\le A_i,B_i,C_i,D_i\le10^9)\)
思路
首先肯定想到排序,但是如果是按照长和宽这两个性质,怎么排都感觉不能做。于是我们考虑把宽度当作第一关键字,当宽度相同,再盒子优先,这样我们就可以保证对于每一块巧克力,它之前的盒子一定是比他宽的,然后它要选择哪个盒子才能最优呢?很容易能想到就是选择在它之前的比它长且长的最少的那个盒子,这样这题差不多就完成了。但是还有一点就是如果一个个找就会显得有点\(naive\),所以我们可以建一棵权值线段树,不过需要对\(D_i\)进行离散化,然后查找的时候就可以区间查询+二分,修改的话单点修改就足够了,能想到这里这道题就能轻松\(AC\)啦!
代码
#include<bits/stdc++.h>
using namespace std;
int A[200005],B[200005],C[200005],D[200005];
struct node
{
int x,y,ty;
bool operator<(const node& b)const
{
if(x!=b.x)return x>b.x;
return ty>b.ty;
}
}a[400005];
int tree[200005<<2];
void update(int p,int l,int r,int w,int x)
{
if(l==r)
{
tree[p]+=w;
return;
}
int mid=(l+r)>>1;
if(x<=mid)update(p<<1,l,mid,w,x);
else update(p<<1|1,mid+1,r,w,x);
tree[p]=tree[p<<1]+tree[p<<1|1];
}
int query(int p,int l,int r,int x,int y)
{
if(x<=l&&r<=y)return tree[p];
int ans=0;
int mid=(l+r)>>1;
if(x<=mid)ans+=query(p<<1,l,mid,x,y);
if(mid<y)ans+=query(p<<1|1,mid+1,r,x,y);
return ans;
}
int aa[200005];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&A[i]);
for(int i=1;i<=n;i++)scanf("%d",&B[i]);
for(int i=1;i<=m;i++)scanf("%d",&C[i]);
for(int i=1;i<=m;i++)scanf("%d",&D[i]);
for(int i=1;i<=n;i++)a[i]={A[i],B[i],1};
for(int i=1;i<=m;i++)
{
a[i+n]={C[i],D[i],2};
aa[i]=D[i];
}
sort(a+1,a+n+m+1);
sort(aa+1,aa+m+1);
int siz=unique(aa+1,aa+m+1)-aa-1;
bool ck=1;
for(int i=1;i<=n+m;i++)
{
if(a[i].ty==2)
{
int id=lower_bound(aa+1,aa+siz+1,a[i].y)-aa;
update(1,1,siz,1,id);
}
else
{
int id=lower_bound(aa+1,aa+siz+1,a[i].y)-aa;
int l=id,r=siz;
while(l<r)
{
int mid=(l+r)>>1;
if(query(1,1,siz,id,mid))r=mid;
else l=mid+1;
}
if(query(1,1,siz,l,l))update(1,1,siz,-1,l);
else {ck=0;break;}
}
}
if(ck)printf("Yes\n");
else printf("No\n");
return 0;
}

浙公网安备 33010602011771号