http://acm.hdu.edu.cn/showproblem.php?pid=4189
题意说是一个数据库,有n(n<=100, 000)个甜甜圈,每个甜甜圈有两个属性l,w. (l,w<10^9)
后面有q个询问,会输入q(q<=50, 000)个罪犯的属性l,w。然后输出每个罪犯与数据库中的资料的最小相似度。相似度是 abs(l1-l2)+abs(w1,w2)。
其实如果把属性看做坐标值的话, 相似度就是两个点的绝对距离。
_____________________________________________________
下面分析,n和q都很大,证明这题不水。。。。
把问题放到坐标图上,我们看着这些一个个的点来讨论。
首先,图上会出现n个坐标点,然后会出现q个询问,让你找出这n个点中,与他绝对距离最小的值。
这个问题也很难处理,还要讨论询问坐标(qx,qy) 与 那n个点的距离没有出现一个规则让你去排序或者贪心来找。
关键就是 abs里面 是会有正负,距离价值无法定位。
那我们再把问题简化,如果我们假设,出现的(qx,qy) 对于任意一个数据库中的 (xi,yi) 都满足 (qx>=xi,qy>=yi) 。
这样的话我们是不是 这个去找 xi+yi 值 尽可能大的值 来使得 dis=(qx-xi)+(qy-yi) 尽可能的小!
上面其实已经把 问题解决了,后面就是代码实现的问题了,我们只需要去 定义四种 规则
1 (qx>=xi,qy>=yi)
2 (qx>=xi,qy<=yi)
3 (qx<=xi,qy>=yi)
4 (qx<=xi,qy<=yi)
后面寻找使得dis 最小的 值
代码的实现我是把n+q个点放一起排序,
比如第一种情况 :在扫到询问点时,满足 qx>xi, 当qx==xi时 qy>=yi
但是在之前的点必然会出现 qx>xi&&qx<yi 这些不满足 (qx>=xi,qy>=yi) 的点。
这个用线段树来规划一下范围,然后在规定的范围内进行查找就不会碰到(qx<yi)的点了。
而扫到数据库中的点,就放入线段树更新。
其实代码可以只扫两边,但是,为了思路明确(关键是懒得改了),我把四种情况都分别排序建树查询。
复杂度 (n+q)*log(n+q)
附上代码
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 #define N 100010 8 #define M 260010 9 typedef long long LL; 10 struct node{ 11 LL x,y; 12 int id; 13 }w[150010]; 14 LL ty[150010],ans[100010]; 15 int ny; 16 struct Tree{ 17 int l,r; 18 LL val; 19 }tree[1050010]; 20 bool cmp1(const node &a,const node &b){ 21 if(a.x!=b.x) return a.x<b.x; 22 if(a.y!=b.y) return a.y<b.y; 23 return a.id<b.id; 24 } 25 bool cmp2(const node &a,const node &b){ 26 if(a.x!=b.x) return a.x<b.x; 27 if(a.y!=b.y) return a.y>b.y; 28 return a.id<b.id; 29 } 30 bool cmp3(const node &a,const node &b){ 31 if(a.x!=b.x) return a.x>b.x; 32 if(a.y!=b.y) return a.y<b.y; 33 return a.id<b.id; 34 } 35 bool cmp4(const node &a,const node &b){ 36 if(a.x!=b.x) return a.x>b.x; 37 if(a.y!=b.y) return a.y>b.y; 38 return a.id<b.id; 39 } 40 int findy(LL y){ 41 int l=0,r=ny-1; 42 while(l<=r){ 43 int mid=(l+r)>>1; 44 if(ty[mid]<y) l=mid+1; 45 else if(ty[mid]>y) r=mid-1; 46 else return mid+1; 47 } 48 } 49 void build(int L,int R,int x){ 50 tree[x].l=L; 51 tree[x].r=R; 52 tree[x].val=1000000000000; 53 if(L==R) return ; 54 int mid=(L+R)>>1; 55 build(L,mid,x<<1); 56 build(mid+1,R,x<<1|1); 57 } 58 LL find(int L,int R,int x){ 59 if(tree[x].l>=L&&tree[x].r<=R) 60 return tree[x].val; 61 62 int mid=(tree[x].l+tree[x].r)>>1; 63 if(R<=mid) return find(L,R,x<<1); 64 if(L>mid) return find(L,R,x<<1|1); 65 return min(find(L,mid,x<<1),find(mid+1,R,x<<1|1)); 66 } 67 void update(int id,int x,LL val){ 68 if(tree[x].l==tree[x].r){ 69 tree[x].val=min(tree[x].val,val); 70 return ; 71 } 72 int mid=(tree[x].l+tree[x].r)>>1; 73 if(id<=mid) update(id,x<<1,val); 74 else update(id,x<<1|1,val); 75 tree[x].val=min(tree[x<<1].val,tree[x<<1|1].val); 76 } 77 int main(){ 78 int n,q,cs=0; 79 while(scanf("%d",&n)&&n!=-1){ 80 if(cs) printf("\n"); 81 else cs=1; 82 for(int i=0;i<n;++i){ 83 scanf("%lld%lld",&w[i].x,&w[i].y); 84 w[i].id=-1; 85 ty[i]=w[i].y; 86 } 87 scanf("%d",&q); 88 for(int i=0;i<q;++i){ 89 ans[i]=1000000000000; 90 scanf("%lld%lld",&w[i+n].x,&w[i+n].y); 91 w[i+n].id=i; 92 ty[i+n]=w[i+n].y; 93 } 94 sort(ty,ty+n+q); 95 ny=0; 96 for(int i=1;i<n+q;++i) 97 if(ty[i]!=ty[ny]) ty[++ny]=ty[i]; 98 ny++; 99 100 101 102 LL my=ty[ny-1],iy=ty[0]; 103 //1 104 build(1,ny,1); 105 sort(w,w+n+q,cmp1); 106 LL mx=w[n+q-1].x,ix=w[0].x; 107 for(int i=0;i<n+q;++i){ 108 if(w[i].id!=-1){ 109 int j=findy(w[i].y); 110 ans[w[i].id]=min(ans[w[i].id],find(1,j,1)-(my-w[i].y)-(mx-w[i].x)); 111 } 112 else update(findy(w[i].y),1,(my-w[i].y)+(mx-w[i].x)); 113 } 114 115 //2 116 build(1,ny,1); 117 sort(w,w+n+q,cmp2); 118 for(int i=0;i<n+q;++i){ 119 if(w[i].id!=-1){ 120 int j=findy(w[i].y); 121 ans[w[i].id]=min(ans[w[i].id],find(j,ny,1)-(w[i].y-iy)-(mx-w[i].x)); 122 } 123 else update(findy(w[i].y),1,(w[i].y-iy)+(mx-w[i].x)); 124 } 125 126 //3 127 build(1,ny,1); 128 sort(w,w+n+q,cmp3); 129 for(int i=0;i<n+q;++i){ 130 if(w[i].id!=-1){ 131 int j=findy(w[i].y); 132 ans[w[i].id]=min(ans[w[i].id],find(1,j,1)-(my-w[i].y)-(w[i].x-ix)); 133 } 134 else update(findy(w[i].y),1,(my-w[i].y)+(w[i].x-ix)); 135 } 136 137 //4 138 build(1,ny,1); 139 sort(w,w+n+q,cmp4); 140 for(int i=0;i<n+q;++i){ 141 if(w[i].id!=-1){ 142 int j=findy(w[i].y); 143 ans[w[i].id]=min(ans[w[i].id],find(j,ny,1)-(w[i].y-iy)-(w[i].x-ix)); 144 } 145 else update(findy(w[i].y),1,(w[i].y-iy)+(w[i].x-ix)); 146 } 147 for(int i=0;i<q;++i) printf("%lld\n",ans[i]); 148 } 149 return 0; 150 }