标签:
1 3 0 0 1 1 2 2
12HintIf palace $ (0,0) $ disappears,$ d = (1-2) ^ 2 + (1 - 2) ^ 2 = 2 $; If palace $ (1,1) $ disappears,$ d = (0-2) ^ 2 + (0 - 2) ^ 2 = 8 $; If palace $ (2,2) $ disappears,$ d = (0-1) ^ 2 + (0-1) ^ 2 = 2 $; Thus the answer is $ 2 + 8 + 2 = 12 $。
分治写法:
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; } const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f; int casenum, casei; struct Point { LL x, y; int o; }p[N], tmpp[N]; int n; LL K(LL x) { return x*x; } struct Ans { int x, y; LL dis; Ans(int x = -1, int y = -1, LL dis = 1e18) :x(x), y(y), dis(dis) {}; void update(Ans b) { if (b.dis < dis) { x = b.x; y = b.y; dis = b.dis; } } }; Ans getDistance(Point &a, Point &b) { LL dis = K(a.x - b.x) + K(a.y - b.y); return Ans(a.o, b.o, dis); } bool cmpxy(const Point& a, const Point& b) { if (a.x != b.x)return a.x < b.x; return a.y < b.y; } bool cmpy(const Point& a, const Point& b) { return a.y < b.y; } Ans res; void Closest_Pair(int l, int r) { if (l + 1 == r) { res.update(getDistance(p[l], p[r])); } else if (l + 2 == r) { res.update(getDistance(p[l], p[l + 1])); res.update(getDistance(p[l + 1], p[r])); res.update(getDistance(p[l], p[r])); } else { int mid = (l + r) >> 1; //先分治求左右子区间内部的最近公共点对 Closest_Pair(l, mid); Closest_Pair(mid + 1, r); //再求左右子区间之间的最近公共点对 int g = 0; for (int i = l; i <= r; ++i) { if (K(p[i].x - p[mid].x) < res.dis)tmpp[g++] = p[i]; } sort(tmpp, tmpp + g, cmpy); for (int i = 0; i < g; ++i) { for (int j = i + 1; j < g && K(tmpp[j].y - tmpp[i].y) < res.dis; ++j) { res.update(getDistance(tmpp[j], tmpp[i])); } } } } int main() { scanf("%d", &casenum); for (casei = 1; casei <= casenum; ++casei) { scanf("%d", &n); for (int i = 0; i < n; i++)scanf("%lld%lld", &p[i].x, &p[i].y); sort(p, p + n, cmpxy); for (int i = 0; i < n; i++)p[i].o = i; res = Ans(); Closest_Pair(0, n - 1); LL ans = res.dis * (n - 2); int x = res.x; int y = res.y; int tmpx = p[x].x; int tmpy = p[x].y; p[x].x = p[x].y = 1e9; res = Ans(); Closest_Pair(0, n - 1); ans += res.dis; p[x].x = tmpx; p[x].y = tmpy; p[y].x = p[y].y = 1e9; res = Ans(); Closest_Pair(0, n - 1); ans += res.dis; printf("%lld\n", ans); } return 0; } /* 【trick&&吐槽】 这题一眼标算,可惜不会模板TwT 最后学习了别人的模板改动过了初测然后FST,血崩! 【题意】 二维平面上有n个点 让你求,在每个点消失一次的情况下,剩余点的最近公共点对距离,并求和。 【类型】 最近公共点对 分治法 or KD-Tree 【分析】 显然,我们只要先求出不删点条件下的最近公共点对距离。 这个距离对答案的贡献系数是(n-2) 然后再分别删掉这2个端点,并再次求最近公共点对求和,答案就出来了。 【时间复杂度&&优化】 O(T * 3nlognlogn) 【数据】 1 5 3 1 1 1 1 3 5 7 5 5 */
#include<iostream> #include<stdio.h> #include<string.h> #include<ctype.h> #include<string> #include<math.h> #include<map> #include<set> #include<vector> #include<queue> #include<algorithm> using namespace std; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; } #define MS(x, y) memset(x, y, sizeof(x)) #define MC(x, y) memcpy(x, y, sizeof(x)) #define lson l,mid-1,(key+1)%Dim #define rson mid+1,r,(key+1)%Dim typedef long long LL; const int Dim = 2; const int N = 100010; int Spe; struct Point { LL p[2]; int o; }p[N], P; int n; struct Ans { int x, y; LL dis; Ans(int x = -1, int y = -1, LL dis = 1e18) :x(x), y(y), dis(dis) {}; void update(Ans b) { if (b.dis < dis) { x = b.x; y = b.y; dis = b.dis; } } }ans; LL K(LL x) { return x*x; } Ans getDistance(Point &a, Point &b) { if (b.o == Spe || a.o == b.o)return Ans(); LL dis = K(a.p[0] - b.p[0]) + K(a.p[1] - b.p[1]); return Ans(a.o, b.o, dis); } int cmpkey; bool cmp(Point x, Point y) { return x.p[cmpkey] < y.p[cmpkey]; } void build(int l, int r, int key) { if (l >= r)return; int mid = (l + r) >> 1; cmpkey = key; nth_element(p + l, p + mid, p + r + 1, cmp); build(lson); build(rson); } void find(int l, int r, int key) { if (l > r)return; int mid = (l + r) >> 1; ans.update(getDistance(P, p[mid])); if (P.p[key] < p[mid].p[key]) { find(lson); if (K(P.p[key] - p[mid].p[key]) < ans.dis)find(rson); } if (P.p[key] > p[mid].p[key]) { find(rson); if (K(P.p[key] - p[mid].p[key]) < ans.dis)find(lson); } } void solve() { int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) { for (int j = 0; j < Dim; ++j)scanf("%lld", &p[i].p[j]); } build(1, n, 0); for (int i = 1; i <= n; ++i)p[i].o = i; ans = Ans(); Spe = 0; LL sum = 0; for (int i = 1; i <= n; ++i) { P = p[i]; find(1, n, 0); } sum += ans.dis*(n - 2); int x = ans.x; int y = ans.y; ans = Ans(); Spe = x; for (int i = 1; i <= n; ++i)if (i != x) { P = p[i]; find(1, n, 0); } sum += ans.dis; ans = Ans(); Spe = y; for (int i = 1; i <= n; ++i)if (i != y) { P = p[i]; find(1, n, 0); } sum += ans.dis; printf("%lld\n", sum); } void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } int casenum, casei; int main() { //fre(); scanf("%d", &casenum); for (casei = 1; casei <= casenum; ++casei)solve(); return 0; } /* 【trick&&吐槽】 这题一眼标算,可惜不会模板TwT 最后学习了别人的模板改动过了初测,然后FST,血崩! 这题还有另外一种KD-tree写法 【题意】 二维平面上有n个点 让你求,在每个点消失一次的情况下,剩余点的最近公共点对距离,并求和。 【类型】 最近公共点对 分治法 or KD-Tree 【分析】 显然,我们只要先求出不删点条件下的最近公共点对距离。 这个距离对答案的贡献系数是(n-2) 然后再分别删掉这2个端点,并再次求最近公共点对求和,答案就出来了。 【时间复杂度&&优化】 O(T * 3nsqrt(n)) 【数据】 1 5 100000 100000 200000 200000 300000 300000 400000 400000 500000 500000 */
【HDU5721 BestCoder 2nd AnniversaryD】【平面最近点对 分治写法+KD-tree写法】Palace 平面最近点对
标签:
原文地址:http://blog.csdn.net/snowy_smile/article/details/51942165