距离学习笔记
各种距离的定义及曼哈顿距离与切比雪夫距离的相互转化可见上文,本文不再赘述
简述题意:给出 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) 计算
分成三种情况,分别是长度为 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 }

浙公网安备 33010602011771号