其实就是建图,多源点最短路。但是呢边数最坏是
O(n2)
级别的,暴力建图会gg(不过数据水,跑的还贼快,快卡掉它吧(逃)
我们发现对于一个点x,他能连向的点是点权在[x,x+d]范围内的点,边权均为1,于是我们可以直接bfs,每个点只入队一次。每次快速的找到未入队的点中能连向的点,并删除即可。我们可以用一个set来支持这个操作。复杂度O(nlogn)
不会自定义比较函数gg,只好set+pair,就需要注意pair比大小的一些细节,一开始都取个负,就可以直接lower_bound了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
#include <utility>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 200010
#define pa pair<int,int>
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,D,a[N],b[N],dis[N];
queue<int>q;
set<pa>sta,stb;set<pa>::iterator it;
int main(){
// freopen("a.in","r",stdin);
n=read();D=read();memset(dis,-1,sizeof(dis));
for(int i=1;i<=n*2;++i) a[i]=-read(),b[i]=-read();
for(int i=1;i<=n;++i){
if(!b[i]) dis[i]=1,q.push(i);
else sta.insert(make_pair(b[i],i));
if(!a[n+i]) dis[n+i]=1,q.push(n+i);
else stb.insert(make_pair(a[n+i],n+i));
}while(!q.empty()){
int x=q.front();q.pop();
if(x<=n){//A<-B
while(1){
it=stb.lower_bound(make_pair(a[x],0));
if(it==stb.end()||it->first>a[x]+D) break;
int y=it->second;stb.erase(*it);dis[y]=dis[x]+1;q.push(y);
}
}else{//B<-A
while(1){
it=sta.lower_bound(make_pair(b[x],0));
if(it==sta.end()||it->first>b[x]+D) break;
int y=it->second;sta.erase(*it);dis[y]=dis[x]+1;q.push(y);
}
}
}for(int i=1;i<=n;++i) printf("%d\n",dis[i]);
return 0;
}