• [bzoj1941][Sdoi2010]Hide and Seek_KD-Tree


    Hide and Seek bzoj-1941 Sdoi-2010

    题目大意:给出平面上n个点,选出一个点,使得距离这个点的最远点曼哈顿距离减去距离这个点的最近非己点的曼哈顿距离最小。输出最小曼哈顿距离差。

    注释:$1le n le 5cdot 10^5$。


    想法:这个题的话处理方法就是枚举所有点,然后对于每一个点求近邻点和“远”邻点。

    其实区别就是估价函数的区别。近邻点对的估价函数就是SJY摆旗子的估价函数

    远邻点的话我们就另设一个估价函数,就表示当前点到这个矩形的可能最远曼哈顿距离。也就是矩形的4个顶点中距离当前点曼哈顿距离最远的曼哈顿距离。

    然后枚举更新答案即可。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 1000010
    #define inf 0x7f7f7f7f 
    using namespace std;
    int ans_min,ans_max,root,d;
    struct Node
    {
    	int c[2],p[2],maxn[2],minn[2];
    }a[N];
    inline bool cmp(const Node &a,const Node &b)
    {
    	return a.p[d]==b.p[d]?a.p[d^1]<b.p[d^1]:a.p[d]<b.p[d];
    }
    void pushup(int k , int s)
    {
        a[k].minn[0] = min(a[k].minn[0] , a[s].minn[0]);
        a[k].minn[1] = min(a[k].minn[1] , a[s].minn[1]);
        a[k].maxn[0] = max(a[k].maxn[0] , a[s].maxn[0]);
        a[k].maxn[1] = max(a[k].maxn[1] , a[s].maxn[1]);
    }
    int build(int l , int r , int now)
    {
        int mid = (l + r) >> 1;
        d = now , nth_element(a + l , a + mid , a + r + 1 , cmp);
        a[mid].minn[0] = a[mid].maxn[0] = a[mid].p[0];
        a[mid].minn[1] = a[mid].maxn[1] = a[mid].p[1];
        if(l < mid) a[mid].c[0] = build(l , mid - 1 , now ^ 1) , pushup(mid , a[mid].c[0]);
        if(r > mid) a[mid].c[1] = build(mid + 1 , r , now ^ 1) , pushup(mid , a[mid].c[1]);
        return mid;
    }
    int getdis_min(int qx,int qy,int x)
    {
    	int ans=0;
    	if(qx<a[x].minn[0]) ans+=a[x].minn[0]-qx;
    	if(qx>a[x].maxn[0]) ans+=qx-a[x].maxn[0];
    	if(qy<a[x].minn[1]) ans+=a[x].minn[1]-qy;
    	if(qy>a[x].maxn[1]) ans+=qy-a[x].maxn[1];
    	return ans;
    }
    int getdis_max(int qx,int qy,int x)
    {
    	int ans=0;
    	ans+=max(abs(qx-a[x].minn[0]),abs(qx-a[x].maxn[0]));
    	ans+=max(abs(qy-a[x].minn[1]),abs(qy-a[x].maxn[1]));
    	return ans;
    }
    void query_min(int qx,int qy,int x)
    {
    	int dis_now=abs(qx-a[x].p[0])+abs(qy-a[x].p[1]);
    	if(dis_now) ans_min=min(dis_now,ans_min);
    	int ls=a[x].c[0],rs=a[x].c[1];
    	int dis_l=ls?getdis_min(qx,qy,ls):inf;
    	int dis_r=rs?getdis_min(qx,qy,rs):inf;
    	if(dis_l<dis_r)
    	{
    		if(ans_min>dis_l) query_min(qx,qy,ls);
    		if(ans_min>dis_r) query_min(qx,qy,rs);
    	}
    	else
    	{
    		if(ans_min>dis_r) query_min(qx,qy,rs);
    		if(ans_min>dis_l) query_min(qx,qy,ls);
    	}
    }
    void query_max(int qx,int qy,int x)
    {
    	int dis_now=abs(qx-a[x].p[0])+abs(qy-a[x].p[1]);
    	ans_max=max(dis_now,ans_max);
    	int ls=a[x].c[0],rs=a[x].c[1];
    	int dis_l=ls?getdis_max(qx,qy,ls):0;
    	int dis_r=rs?getdis_max(qx,qy,rs):0;
    	if(dis_l>dis_r)
    	{
    		if(ans_max<dis_l) query_max(qx,qy,ls);
    		if(ans_max<dis_r) query_max(qx,qy,rs);
    	}
    	else
    	{
    		if(ans_max<dis_r) query_max(qx,qy,rs);
    		if(ans_max<dis_l) query_max(qx,qy,ls);
    	}
    }
    int main()
    {
    	int n,ans=inf; cin >> n ;
    	for(int i=1;i<=n;i++) scanf("%d%d",&a[i].p[0],&a[i].p[1]);
    	root=build(1,n,1);
    	for(int i=1;i<=n;i++)
    	{
    		ans_min=inf,ans_max=0;
    		query_min(a[i].p[0],a[i].p[1],root), query_max(a[i].p[0],a[i].p[1],root);
    		ans=min(ans,ans_max-ans_min);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    小结:KD-Tree如果觉得复杂度不对就不对吧,这题就是驶过的。还有,那个tm30秒我还以为是每个店周围的斜正方形之内的点,然后一顿敲就是过不去样例,还没有样例解释...差评!

  • 相关阅读:
    监视用户是保存用户编辑还是放弃参照编辑
    AutoCAD: 添加鼠标快捷键/鼠标右键
    C# List<T>集合布尔运算
    List<T>的用法详解
    天正的坑
    C#札记
    AUTOCAD2013 以上利用ACCORECONSOLE+ SCR后台批量清理图纸
    BaiduSitemap
    三一邮件群发
    Windows+IIS+Mysql+php安装
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9393066.html
Copyright © 2020-2023  润新知