标签:
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