zoukankan      html  css  js  c++  java
  • 【52.55%】【BZOJ 4520】K远点对

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 588  Solved: 309
    [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

    Sample Output

    9

    【题解】

    第K远点对。是说C(N,2)个点对里面。点对之间的距离是第K远的。求这个距离。

    我们枚举每个点。然后查看它与其他点的距离。

    维护一个1..2*K远的队列。然后不断更新这个队列

    (为什么是2*k,想想我们在枚举第一个点的时候,假如和第3个点配对,距离为第2远那么下次再枚举第3个点的时候还会遇到第一个点。又出现了一个第2远的数要加入到队列中。而这两个距离其实是同一个点对的。即排列。考虑其他第1,3,4,..k远的点对也会出现这种情况。我们就把K变成2*K。);

    【代码】

    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int MAX_N = 109000;
    
    int n, k,root,now;
    long long duilie[300];
    
    struct point
    {
    	long long d[2], mi_n[2], ma_x[2] ;
    	int l,r;
    };
    
    point t[MAX_N],op;
    
    void input_data()
    {
    	scanf("%d%d", &n, &k);
    	for (int i = 1; i <= n; i++)
    		scanf("%lld%lld", &t[i].d[0], &t[i].d[1]);
    }
    
    bool cmp(point a, point b)
    {
    	return a.d[now] < b.d[now];
    }
    
    void up_data(int rt)
    {
    	int l = t[rt].l, r = t[rt].r;
    	for (int i = 0; i <= 1; i++)
    	{
    		if (l)
    		{
    			t[rt].ma_x[i] = max(t[rt].ma_x[i], t[l].ma_x[i]);
    			t[rt].mi_n[i] = min(t[rt].mi_n[i], t[l].mi_n[i]);
    		}
    		if (r)
    		{
    			t[rt].ma_x[i] = max(t[rt].ma_x[i], t[r].ma_x[i]);
    			t[rt].mi_n[i] = min(t[rt].mi_n[i], t[r].mi_n[i]);
    		}
    	}
    }
    
    int build(int begin, int end, int fx)
    {
    	int m = (begin + end) >> 1;
    	now = fx;
    	nth_element(t + begin, t + m, t + end + 1, cmp);
    	for (int i = 0; i <= 1; i++)
    		t[m].ma_x[i] = t[m].mi_n[i] = t[m].d[i];
    	if (begin < m)
    		t[m].l = build(begin, m - 1, 1 - fx);
    	if (m < end)
    		t[m].r = build(m + 1, end, 1 - fx);
    	up_data(m);
    	return m;
    }
    
    long long sqr(long long x)
    {
    	return x*x;
    }
    
    long long get_dis(int rt)
    {
    	return sqr(t[rt].d[0] - op.d[0]) + sqr(t[rt].d[1] - op.d[1]);
    }
    
    long long gujia(int rt)//估价函数
    {
    	long long temp = 0;
    	for (int i = 0; i <= 1; i++)
    		temp += max(sqr(t[rt].mi_n[i] - op.d[i]), sqr(t[rt].ma_x[i] - op.d[i]));
    	return temp;
    }
    
    void query(int rt)
    {
    	long long dis = get_dis(rt);
    	int k_th = k;
    	while (duilie[k_th] <= dis)//找到这个距离在队列中的合适位置。
    	{
    		k_th--;
    		if (!k_th)
    			break;
    	}
    	if (k_th != k)
    	{
    		for (int i = k; i >= k_th + 2; i--)
    			duilie[i] = duilie[i - 1];//这个位置后面的数字往后挪。
    		duilie[k_th + 1] = dis;
    	}
    	int l = t[rt].l, r = t[rt].r;
    	long long gl = -1,gr = -1;
    	if (l)
    		gl = gujia(l);
    	if (r)
    		gr = gujia(r);
    	if (gl < gr)
    	{
    		if (gr >= duilie[k])
    			query(r);
    		if (gl >= duilie[k])
    			query(l);
    	}
    	else
    	{
    		if (gl >= duilie[k])
    			query(l);
    		if (gr >= duilie[k])
    			query(r);
    	}
    }
    
    void get_ans()
    {
    	root = build(1, n, 0);
    	k = k * 2;//直接求2*k远
    	for (int i = 1; i <= k; i++)//duilie[1..k]分别表示第1,2,3..远。因此它是递减队列。
    		duilie[i] = 0;
    	for (int i = 1; i <= n; i++)
    	{
    		op.d[0] = t[i].d[0], op.d[1] = t[i].d[1];
    		query(root);
    	}
    }
    
    void output_ans()
    {
    	printf("%lld
    ", duilie[k]);
    }
    
    int main()
    {
    	//freopen("F:\rush.txt", "r", stdin);
    	input_data();
    	get_ans();
    	output_ans();
    	return 0;
    }


  • 相关阅读:
    Ubuntu+Windows双系统升级Windows启动项消失恢复
    day19 Servlet Filter
    day17 dbutils 和 jdbc 多表操作
    day16 事务
    day15 分页及 JDBC 大数据的处理
    day14 JDBC
    day13 MySQL 及数据库相关
    Windows系统中完全卸载MySQL数据库,实现重装
    Elasticsearch 6.5.4 安装IK Analysis插件
    js 常用功能
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632234.html
Copyright © 2011-2022 走看看