题目:两只牛,牛A和牛B,他们对水果派的品味不同,每个人都有n<=1e5个派,每个派都有两种得分a[i], b[i],其中a[i]是牛A对该派的评分,b[i]是牛B的评分, 0 <= a[i], b[i] <= 1e9。两只牛开始礼尚往来,从牛A开始,它选一个pie给牛B,设这个pie的评分是(a[i], b[i])。此时牛B为了不失礼节(不太小气,也不要太谄媚)要选出一个B
评分在[b[i], b[i]+d]范围内的pie(a[j], b[j]),给A。同理,A又要选出一个A评分在[a[j], a[j]+d]范围内的pie给B,如此往复。每个pie都只能传递一次。如果A收到了一个A评分为0的pie,或者B收到了一个B评分为0的pie,那么礼尚往来就愉快的结束了。否则,就不愉快结束(即一个人无法选出合法的pie给对方时)。下面让你输出,
对于A的每一个pie,如果第一轮A把这个pie交给B,礼尚往来最少可以几轮愉快结束?如果无法愉快结束,就输出-1
Solution:
我们考虑倒推,首先,A的pie中b[i]=0的部分肯定只要一步就能完成,B的pie同理,我们将他们加进队列,然后依次用这些队列中的点去更新,我们取出一个点,如果是A的pie,那么那些B的pie能到它呢?设A的pie为(a[i],b[i]),则B的pie(a[j],b[j])需要满足a[i]-D<=a[j]<=a[i],我们就可以将B按a数组排序,每次就可以二分查找了。
但是加入数据厉害让你所有都匹配上就是N^2级别的匹配了,怎么办?设dis为答案注意到dis先确定的小,也就是说不会变了,那我们就可以把改好的连接起来,加速,这个过程可以用并查集实现,
for (int i=l,father;i<=r;i=father+1)
{
father=find(i);
fa[i]=r;
if (dis[i]>dis[u]+1)
dis[i]=dis[u]+1,q[R++]=i;
}
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=400010;
int fa[M],dis[M],q[M],ans[M];
int N,D,L,R;
struct node{
int A,B,id;
}a[M];
bool cmp1(const node &a, const node &b)
{return a.B<b.B;}
bool cmp2(const node &a, const node &b)
{return a.A<b.A;}
int find(int x)
{return fa[x]==x?x:fa[x]=find(fa[x]);}
int bin1(int l,int r,int x)
{
if (a[r].A<x) return -1;
while (l<r)
{
int mid=(l+r)>>1;
if (a[mid].A<x) l=mid+1;
else r=mid;
}
return r;
}
int bin2(int l,int r,int x)
{
if (a[l].A>x) return -1;
while (l<r)
{
int mid=(l+r+1)>>1;
if (a[mid].A>x) r=mid-1;
else l=mid;
}
return l;
}
int bin3(int l,int r,int x)
{
if (a[r].B<x) return -1;
while (l<r)
{
int mid=(l+r)>>1;
if (a[mid].B<x) l=mid+1;
else r=mid;
}
return r;
}
int bin4(int l,int r,int x)
{
if (a[l].B>x) return -1;
while (l<r)
{
int mid=(l+r+1)>>1;
if (a[mid].B>x) r=mid-1;
else l=mid;
}
return l;
}
int main()
{
L=R=0;
scanf("%d%d",&N,&D);
for (int i=1;i<=2*N;i++)
{
scanf("%d%d",&a[i].A,&a[i].B);
a[i].id=i; fa[i]=i;
}
sort(a+1,a+1+N,cmp1);
sort(a+1+N,a+1+N+N,cmp2);
memset(dis,0x3f,sizeof(dis));
for (int i=1;i<=N && !a[i].B;i++)
q[R++]=i,dis[i]=1;
for (int i=N+1;i<=N+N && !a[i].A;i++)
q[R++]=i,dis[i]=1;
while (L<R)
{
int u=q[L++],l,r;
if (u<=N)
{
l=bin1(N+1,N+N,a[u].A-D);
r=bin2(N+1,N+N,a[u].A);
}
else
{
l=bin3(1,N,a[u].B-D);
r=bin4(1,N,a[u].B);
}
if (l==-1 || r==-1) continue;
for (int i=l,father;i<=r;i=father+1)
{
father=find(i);
fa[i]=r;
if (dis[i]>dis[u]+1)
dis[i]=dis[u]+1,q[R++]=i;
}
}
for (int i=1;i<=N;i++)
ans[a[i].id]=dis[i];
for (int i=1;i<=N;i++)
if (ans[i]<0x3f3f3f3f) printf("%d\n",ans[i]);
else puts("-1");
return 0;
}