正题
题目链接:https://www.ybtoj.com.cn/contest/66/problem/4
题目大意
平面上nnn个红点,nnn个蓝点,对于没一个红点求一个与它纵坐标距离不超过ddd的一个点与它的曼哈顿距离最短。
解题思路
一个点分为两种情况,在询问点左边的红点要求横坐标大,在询问点右边的红点要求横坐标小,为了方便,我们开两个线段树。
依次从上往下扫描点,然后将蓝点加入两个线段树中,注意扫描位置变换时我们要让所有加入的点的值加上一个移动的距离(即纵坐标的距离差)。然后因为要把加入的超出范围的点弹出去,所以我们在线段树的每个叶子处维护一个堆即可。
然后正反各扫一次即可。
因为叶子处维护,所以堆和线段树实际复杂度是分开的,时间复杂度O(nlogn)O(n\log n)O(nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+10,Lim=1e8,inf=1e9;
struct point{int x,y,dl,dr;
}a[N],b[N];
int n,d,cnt,c[N<<1],ans[N];
struct Heap{priority_queue<int> q1,q2;void push(int x){q1.push(x);return;}void pop(int x){q2.push(x);return;}bool empty(){return (q1.size()-q2.size())==0;}int top(){while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();return q1.top();}void clear(){while(!q1.empty())q1.pop();while(!q2.empty())q2.pop();return;}
};
struct node{Heap q[N<<3];int w[N<<3],lazy[N<<3];void Clear(){for(int i=1;i<N<<3;i++)w[i]=-inf,lazy[i]=0,q[i].clear();}void Downdata(int x){if(!lazy[x])return;lazy[x*2]+=lazy[x];lazy[x*2+1]+=lazy[x];w[x*2]+=lazy[x];w[x*2+1]+=lazy[x];lazy[x]=0;return;}void Push(int x,int l,int r,int pos,int &val){if(l==r){val-=lazy[x];q[x].push(val);if(!q[x].empty())w[x]=q[x].top()+lazy[x];else w[x]=-inf;return;}int mid=(l+r)>>1;Downdata(x);if(pos<=mid)Push(x*2,l,mid,pos,val);else Push(x*2+1,mid+1,r,pos,val);w[x]=max(w[x*2],w[x*2+1]);return;}void Pop(int x,int l,int r,int pos,int val){if(l==r){q[x].pop(val);if(!q[x].empty())w[x]=q[x].top()+lazy[x];else w[x]=-inf;return;}int mid=(l+r)>>1;Downdata(x);if(pos<=mid)Pop(x*2,l,mid,pos,val);else Pop(x*2+1,mid+1,r,pos,val);w[x]=max(w[x*2],w[x*2+1]);return;} int Ask(int x,int L,int R,int l,int r){if(l>r)return -inf; if(L==l&&R==r)return w[x];int mid=(L+R)>>1;Downdata(x);if(r<=mid)return Ask(x*2,L,mid,l,r);if(l>mid)return Ask(x*2+1,mid+1,R,l,r);return max(Ask(x*2,L,mid,l,mid),Ask(x*2+1,mid+1,R,mid+1,r)); }
}Tl,Tr;
bool cmp(point x,point y)
{return x.x<y.x;}
void work(){sort(a+1,a+1+n,cmp);sort(b+1,b+1+n,cmp);int l=1,r=1;Tl.Clear();Tr.Clear();for(int i=1;i<=n;i++){if(i!=1){Tl.lazy[1]-=b[i].x-b[i-1].x;Tr.lazy[1]-=b[i].x-b[i-1].x;Tl.w[1]-=b[i].x-b[i-1].x;Tr.w[1]-=b[i].x-b[i-1].x;}while(r<=n&&a[r].x<=b[i].x){int w=lower_bound(c+1,c+1+cnt,a[r].y)-c;Tl.Push(1,1,cnt,w,a[r].dl=a[r].y-b[i].x+a[r].x);Tr.Push(1,1,cnt,w,a[r].dr=Lim-a[r].y-b[i].x+a[r].x);r++;}while(l<=n&&b[i].x-a[l].x>d){int w=lower_bound(c+1,c+1+cnt,a[l].y)-c;Tl.Pop(1,1,cnt,w,a[l].dl);Tr.Pop(1,1,cnt,w,a[l].dr);l++;}int w=lower_bound(c+1,c+1+cnt,b[i].y)-c;ans[b[i].dl]=min(ans[b[i].dl],b[i].y-Tl.Ask(1,1,cnt,1,w));ans[b[i].dl]=min(ans[b[i].dl],Lim-Tr.Ask(1,1,cnt,w+1,cnt)-b[i].y);}
}
int main()
{freopen("portal.in","r",stdin);freopen("portal.out","w",stdout);scanf("%d%d",&n,&d);for(int i=1;i<=n;i++)scanf("%d%d",&b[i].x,&b[i].y),b[i].dl=i,swap(b[i].x,b[i].y),c[i+n]=b[i].y;for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y),swap(a[i].x,a[i].y),c[i]=a[i].y;sort(c+1,c+1+2*n);memset(ans,0x3f3f3f3f,sizeof(ans));cnt=unique(c+1,c+1+2*n)-c-1;work();for(int i=1;i<=n;i++)a[i].x=Lim-a[i].x,b[i].x=Lim-b[i].x;work();for(int i=1;i<=n;i++)if(ans[i]>=1e9)printf("0\n");else printf("%d\n",ans[i]);return 0;
}