[bzoj1941][sdoi2010]Hide and Seek

传送门

Description

平面上\(n\)个点,一个点的贡献是离他最远的点的距离减去离他最近的点的距离,求最小的贡献

距离是曼哈顿距离

\(n\leq 500000\)

Solution 

k-d tree 模板题

建树过程相当于每次按照一维把超平面上的点进行划分,\(O(n\log n)\)

用到函数

std::nth_element(a+l,a+mid,a+r+1);

可以取得排序后的中位数

k-d tree 常用来解决平面最近点问题

最坏复杂度为\(O(\sqrt n)\),平均复杂度是\(O(\log n)\)

对于查找一个节点的最近点

从根开始,假设当前递归到一个节点,先用这个点更新答案。

然后对于它的两个孩子,优先选择离当前点近的一个矩形,递归更新答案

然后更新完答案如果到另一个儿子的那个矩形距离比答案小就也用另一个儿子递归更新答案。

一个节点到矩形的距离指的是到矩形边界的最远距离,显然这个值不一定能取到


Code 

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define abs(x) ((x)>0?(x):-(x))
#define reg register
inline int read()
{
	int 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<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}

const int MN=5e5+5,inf=0x3f3f3f3f;
int n,mn,mx,now;
struct Point{
	int d[2],mx[2],mn[2],l,r;
    int& operator[](int x){return d[x];}
    bool operator<(const Point&x)const{return d[now]<x.d[now];}
    friend int dis(Point x,Point y){return abs(x.d[0]-y.d[0])+abs(x.d[1]-y.d[1]);}
}a[MN];

struct KDtree{
	Point p[MN],T;
	void up(int x)
	{
		int l=p[x].l,r=p[x].r;
		for(reg int i=0;i<2;++i)
		{
			if(l) p[x].mn[i]=min(p[x].mn[i],p[l].mn[i]),
                  p[x].mx[i]=max(p[x].mx[i],p[l].mx[i]);
            if(r) p[x].mn[i]=min(p[x].mn[i],p[r].mn[i]),
                  p[x].mx[i]=max(p[x].mx[i],p[r].mx[i]);
		}
	}
    int getmn(Point x)
    {
        reg int r=0;
        for(reg int i=0;i<2;++i)
            r+=max(x.mn[i]-T[i],0),r+=max(T[i]-x.mx[i],0); 
        return r;
    }
    int getmx(Point x)
    {
        reg int r=0;
        for(reg int i=0;i<2;++i)
            r+=max(abs(x.mn[i]-T[i]),abs(x.mx[i]-T[i]));
        return r;
    }
    int build(int l,int r,int th)
    {
    	if(l>r) return 0;
        reg int mid=(l+r)>>1;now=th;
        std::nth_element(a+l,a+mid,a+r+1);p[mid]=a[mid];
        for(reg int i=0;i<2;++i) p[mid].mx[i]=p[mid].mn[i]=a[mid][i];
        p[mid].l=build(l,mid-1,th^1);p[mid].r=build(mid+1,r,th^1);up(mid);
        return mid;
    }
    void qmn(int k)
    {
        int t=dis(p[k],T);if(t)mn=min(mn,t);
        int dl=inf,dr=inf;
        if(p[k].l) dl=getmn(p[p[k].l]);
        if(p[k].r) dr=getmn(p[p[k].r]);    
        if(dl>dr){if(dr<mn) qmn(p[k].r);if(dl<mn)qmn(p[k].l);}
        else{if(dl<mn)qmn(p[k].l);if(dr<mn)qmn(p[k].r);}
    }
    void qmx(int k)
    {
        mx=max(mx,dis(p[k],T));
        int dl=-inf,dr=-inf;
        if(p[k].l) dl=getmx(p[p[k].l]);
        if(p[k].r) dr=getmx(p[p[k].r]);
        if(dl>dr){if(dl>mx) qmx(p[k].l);if(dr>mx)qmx(p[k].r);} 
        else{if(dr>mx) qmx(p[k].r);if(dl>mx)qmx(p[k].l);}
    } 
}kdtree;
int rt,ans;

int main()
{
	n=read();
	reg int i;
	for(i=1;i<=n;++i) a[i][0]=read(),a[i][1]=read();
	rt=kdtree.build(1,n,0);
	for(ans=inf,i=1;i<=n;++i)
	{
		kdtree.T=a[i];
		mn=inf;kdtree.qmn(rt);
		mx=-inf;kdtree.qmx(rt);
		ans=min(ans,mx-mn);
	}
	return 0*printf("%d\n",ans);
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2019-05-07 23:13  PaperCloud  阅读(233)  评论(0编辑  收藏  举报