距离学习笔记

推荐阅读:常用距离算法详解(我就在这里学的

各种距离的定义及曼哈顿距离与切比雪夫距离的相互转化可见上文,本文不再赘述


例题1:松鼠聚会

简述题意:给出 n 个点,求出一个点使之到其他点的切比雪夫距离之和最小 

把切比雪夫距离转化为曼哈顿距离

若答案点为 k ,即求 $\sum_{i=1}^{n}(|x_i-x_k|+|y_i-y_k|)$

将 x 和 y 分开来算: $\sum_{i=1}^{n}|x_i-x_k|+\sum_{i=1}^{n}|y_i-y_k|$

先算 x ,发现绝对值不好计算,考虑将其拆开:将 x 排序,将 $x_i < x_k$ 的分成一部分,$x_i > x_k$ 的部分分成一部分

则有 $\sum_{i=1}^{k-1}(x_k-x_i)+\sum_{i=k+1}^{n}(x_i-x_k)$

再将括号拆开,则有 $(k-1)x_k-\sum_{i=1}^{k-1}x_i+\sum_{i=k+1}^{n}x_i-(n-k)x_k$

前后两项显然可以 O(1) 计算,中间两项是连续子序列之和,直接前缀和即可 O(1) 计算


 

例题2:[IOI2007]pairs

分成三种情况,分别是长度为 M 的线段 ($M \leq 7.5*10^7$),M * M 的正方形 ($M \leq 75000$),和 M * M * M 的立方体 ($M \leq 75$)

每种物体上有 n 个点 ($n \leq 100000$),求满足点对 (a,b) 中点 a 和点 b 间曼哈顿距离小于等于 D 的点对数量

分开讨论,对于

一维情况

直接排序后枚举点,二分出 x - d 的位置即可(不必计算 x + d 是因为会有重复)

二维情况

曼哈顿转切比雪夫,按 y 排序后枚举点 i ,将 $y < y_i - d$ 的点扔掉,这样只需要考虑 $[y_i - d, y_i]$ 间的点的 x 有几个满足条件即可

发现 $M \leq 75000$,可以直接用树状数组,设树状数组当前位置是 x,则树状数组用来记录 点横坐标 大于等于 x 的点的数量

三维情况:

有点难搞,但是需要注意到 M 很小,最大只有 75

首先把横坐标和纵坐标转成切比雪夫坐标,现在即把 $|x_i-x_k|+|y_i-y_k|+|z_i-z_k|$ 转化成了 $\max\{|x_i-x_k|,|y_i-y_k|\}+|z_i-z_k|$

那么我们枚举点 k,从 1 向 $z_k$ 枚举当前 z 坐标 z,那么我们只需要求出 z 这个平面上与 k 点的切比雪夫距离为小于等于 $(d-z)$ 的点的数量即可

观察到 M 极小,考虑用二维前缀和统计每个平面的点的数量

需要注意一个小细节,在 $z_k$ 这个平面上直接统计会有重复,需要除以 2

  1 // P4648 [IOI2007] pairs 动物对数
  2 
  3 #include <ctime>
  4 #include <cmath>
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <cstdlib>
  8 #include <iostream>
  9 #include <algorithm>
 10 #include <vector>
 11 #include <queue>
 12 #define inf 100010
 13 #define INF 0x7fffffff
 14 #define ll long long
 15 
 16 namespace io {
 17     const int SIZE = (1 << 21) + 1;
 18     char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
 19     
 20     #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
 21     
 22     inline void flush () {
 23         fwrite (obuf, 1, oS - obuf, stdout);
 24         oS = obuf;
 25     }
 26     
 27     inline void putc (char x) {
 28         *oS ++ = x;
 29         if (oS == oT) flush ();
 30     }
 31     
 32     template <class I>
 33     inline void read (I &x) {
 34         for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
 35         for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); 
 36         x *= f;
 37     }
 38     
 39     template <class I>
 40     inline void print (I x) {
 41         if (!x) putc ('0'); 
 42         if (x < 0) putc ('-'), x = -x;
 43         while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
 44         while (qr) putc (qu[qr --]);
 45     }
 46     
 47     struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
 48 }
 49 using io :: read; using io :: putc; using io :: print;
 50 template <class I>
 51 inline void read(I &a, I &b) {read(a); read(b);}
 52 template <class I>
 53 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);}
 54 
 55 int B, n, d, m, mm;
 56 int x[inf], y[inf], z[inf];
 57 
 58 namespace case1 {
 59     ll ans;
 60 
 61     inline bool cmp (const int &a, const int &b) {
 62         return a < b;
 63     }
 64 
 65     inline void solve() {
 66         std::sort(x + 1, x + 1 + n, cmp);
 67         for(int i = 1; i <= n; i++) {
 68             int p = std::lower_bound(x + 1, x + 1 + n, x[i] - d) - x;
 69             ans += i - p;
 70         }
 71         printf("%lld\n", ans);
 72     }
 73 }
 74 
 75 namespace case2 {
 76     struct Node {
 77         int x, y;
 78     };
 79 
 80     struct ArrayTree {
 81 #define lowbit(a) ((a) & (-(a)))
 82         int c[inf << 1];
 83 
 84         inline void add(int x, int k) {
 85             while(x <= mm) {
 86                 c[x] += k;
 87                 x += lowbit(x);
 88             }
 89         }
 90 
 91         inline int query(int x) {
 92             ll ans = 0;
 93             while(x) {
 94                 ans += c[x];
 95                 x -= lowbit(x);
 96             }
 97             return ans;
 98         }
 99 #undef lowbit
100     };
101 
102     ll ans;
103     Node a[inf];
104     ArrayTree tree;
105 
106     inline bool cmp (const Node &a, const Node &b) {
107         return a.y < b.y;
108     }
109 
110     inline void solve() {
111         for(int i = 1; i <= n; i++) {
112             a[i].x = x[i] + y[i];
113             a[i].y = x[i] - y[i] + m;
114         }
115         std::sort(a + 1, a + 1 + n, cmp);
116         int j = 1;
117         for(int i = 1; i <= n; i++) {
118             while(a[i].y - a[j].y > d) tree.add(a[j].x, -1), j++;
119             ans += (tree.query(std::min(a[i].x + d, mm)) - tree.query(std::max(a[i].x - d - 1, 0)));
120             tree.add(a[i].x, 1);
121         }
122         printf("%lld\n", ans);
123     }
124 }
125 
126 namespace case3 {
127 #define N 80
128     struct Node {
129         int x, y, z;
130     };
131 
132     ll ans;
133     Node a[inf];
134     int bucket[N << 1][N << 1][N];
135     int sum[N << 1][N << 1][N];
136 
137     inline bool cmp(const Node &a, const Node &b) {
138         return a.z < b.z;
139     }
140 
141     inline int getans(int z, int now, int d) { // in z: (x - d) -> (x + d) & (y - d) -> (y + d)
142         int ur = sum[std::min(mm, a[now].x + d)][std::min(mm, a[now].y + d)][z]; // +
143         int dr = sum[std::min(mm, a[now].x + d)][std::max(0, a[now].y - d - 1)][z]; // -
144         int ul = sum[std::max(0, a[now].x - d - 1)][std::min(mm, a[now].y + d)][z]; // -
145         int dl = sum[std::max(0, a[now].x - d - 1)][std::max(0, a[now].y - d - 1)][z]; // +
146         return ur - dr - ul + dl;
147     }
148 
149     inline void solve() {
150         for(int i = 1; i <= n; i++) {
151             a[i].x = x[i] + y[i];
152             a[i].y = x[i] - y[i] + m;
153             a[i].z = z[i];
154             ++bucket[a[i].x][a[i].y][a[i].z];
155         }
156         for(int k = 1; k <= m; k++) { // z
157             for(int i = 1; i <= mm; i++) { // x
158                 for(int j = 1; j <= mm; j++) { // y
159                     sum[i][j][k] = bucket[i][j][k] + sum[i - 1][j][k] + sum[i][j - 1][k] - sum[i - 1][j - 1][k];
160                 }
161             }
162         }
163         std::sort(a + 1, a + 1 + n, cmp);
164         for(int i = 1; i <= n; i++) {
165             for(int j = std::max (1, a[i].z - d); j < a[i].z; j++) {
166                  if(a[i].z - j > d) continue;
167                 int newd = d - (a[i].z - j);
168                 ans += getans(j, i, newd);
169             }
170         }
171         int tmp = 0;
172         for(int i = 1; i <= n; i++) tmp += getans(a[i].z, i, d) - 1;
173         ans += (tmp >> 1);
174         printf("%lld\n", ans);
175     }
176 }
177 
178 inline void setting(){
179 #ifndef ONLINE_JUDGE
180     freopen("_test.in", "r", stdin);
181     freopen("_test.out", "w", stdout);
182 #endif
183     return;
184 }
185 
186 signed main () {
187     setting();
188     read(B); read(n, d, m);
189     mm = m << 1;
190     for(int i = 1; i <= n; i++) {
191         if(B == 1) read(x[i]);
192         if(B == 2) read(x[i], y[i]);
193         if(B == 3) read(x[i], y[i], z[i]);
194     }
195     if(B == 1) case1::solve();
196     if(B == 2) case2::solve();
197     if(B == 3) case3::solve();
198     return 0;
199 }

 

posted @ 2020-08-01 11:27  Chiaro  阅读(245)  评论(0)    收藏  举报