【BZOJ-4520】K远点对 KD-Tree + 堆
4520: [Cqoi2016]K远点对
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 490 Solved: 237
[Submit][Status][Discuss]
Description
已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对。
Input
输入文件第一行为用空格隔开的两个整数 N, K。接下来 N 行,每行两个整数 X,Y,表示一个点
的坐标。1 < = N < = 100000, 1 < = K < = 100, K < = N*(N−1)/2 , 0 < = X, Y < 2^31。
Output
输出文件第一行为一个整数,表示第 K 远点对的距离的平方(一定是个整数)。
Sample Input
10 5
0 0
0 1
1 0
1 1
2 0
2 1
1 2
0 2
3 0
3 1
0 0
0 1
1 0
1 1
2 0
2 1
1 2
0 2
3 0
3 1
Sample Output
9
HINT
Source
Solution
正解似乎是维护凸包!@#%……
不过KD Tree暴力搞就可以了,而且实测效率很高
具体的做法就是:先将平面上的所有点加入KDTree中,然后维护一个小根堆,枚举每个点进行询问
小根堆的用途及相当于当前最优解为小根堆的堆顶
Attention:
有些点会被计算两次,所以堆中实际是2*k个元素
注意开longlong,极限值的取值
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<queue> #include<cstdlib> using namespace std; long long read() { long long x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define maxn 100010 #define inf 100000000000000000LL int n,k,D; long long sqr(long long a) {return (long long)(a*a);} struct PointNode { int l,r; long long d[2],maxx[2],minn[2]; bool operator < (const PointNode & A) const {return d[D]<A.d[D];} PointNode (long long x=0,long long y=0) {l=r=0; d[0]=x; d[1]=y;} }p[maxn]; priority_queue<long long, vector<long long>, greater<long long> > heap; long long dis(PointNode A,PointNode B) {return sqr(A.d[1]-B.d[1])+sqr(A.d[0]-B.d[0]);} struct KDTreeNode { int rt; PointNode Point,tree[maxn<<1]; void Update(int now) { for (int i=0; i<=1; i++) { tree[now].minn[i]=tree[now].maxx[i]=tree[now].d[i]; if (tree[now].l) tree[now].minn[i]=min(tree[tree[now].l].minn[i],tree[now].minn[i]),tree[now].maxx[i]=max(tree[tree[now].l].maxx[i],tree[now].maxx[i]); if (tree[now].r) tree[now].minn[i]=min(tree[tree[now].r].minn[i],tree[now].minn[i]),tree[now].maxx[i]=max(tree[tree[now].r].maxx[i],tree[now].maxx[i]); } } int BuildTree(int l,int r,int dd) { int mid=(l+r)>>1; D=dd; nth_element(p+l,p+mid,p+r+1); tree[mid]=p[mid]; for (int i=0; i<=1; i++) tree[mid].minn[i]=tree[mid].maxx[i]=tree[mid].d[i]; if (l<mid) tree[mid].l=BuildTree(l,mid-1,dd^1); if (r>mid) tree[mid].r=BuildTree(mid+1,r,dd^1); Update(mid); return mid; } long long dist(int pl,PointNode P) { long long re=0; for (int i=0; i<=1; i++) re+=max(sqr(P.d[i]-tree[pl].minn[i]),sqr(P.d[i]-tree[pl].maxx[i])); return re; } void Query(int now) { long long dl,dr,d0; d0=dis(tree[now],Point); if (d0>heap.top()) heap.pop(),heap.push(d0); if (tree[now].l) dl=dist(tree[now].l,Point); else dl=-inf; if (tree[now].r) dr=dist(tree[now].r,Point); else dr=-inf; if (dl>dr) { if (dl>heap.top()) Query(tree[now].l); if (dr>heap.top()) Query(tree[now].r); } else { if (dr>heap.top()) Query(tree[now].r); if (dl>heap.top()) Query(tree[now].l); } } }KDTree; int main() { // freopen("farthest.in","r",stdin); // freopen("farthest.out","w",stdout); n=read(); k=read(); for (int x,y,i=1; i<=n; i++) x=read(),y=read(),p[i]=PointNode(x,y); KDTree.rt=KDTree.BuildTree(1,n,0); for (int i=1; i<=k+k; i++) heap.push(0LL); for (int i=1; i<=n; i++) KDTree.Point=p[i],KDTree.Query(KDTree.rt); printf("%lld\n",heap.top()); return 0; }
——It's a lonely path. Don't make it any lonelier than it has to be.