zoukankan      html  css  js  c++  java
  • bzoj 1941: [Sdoi2010]Hide and Seek

    Description

    小猪iPig在PKU刚上完了无聊的猪性代数课,天资聪慧的iPig被这门对他来说无比简单的课弄得非常寂寞,为了消除寂寞感,他决定和他的好朋友giPi(鸡皮)玩一个更加寂寞的游戏---捉迷藏。 但是,他们觉得,玩普通的捉迷藏没什么意思,还是不够寂寞,于是,他们决定玩寂寞无比的螃蟹版捉迷藏,顾名思义,就是说他们在玩游戏的时候只能沿水平或垂直方向走。一番寂寞的剪刀石头布后,他们决定iPig去捉giPi。由于他们都很熟悉PKU的地形了,所以giPi只会躲在PKU内n个隐秘地点,显然iPig也只会在那n个地点内找giPi。游戏一开始,他们选定一个地点,iPig保持不动,然后giPi用30秒的时间逃离现场(显然,giPi不会呆在原地)。然后iPig会随机地去找giPi,直到找到为止。由于iPig很懒,所以他到总是走最短的路径,而且,他选择起始点不是随便选的,他想找一个地点,使得该地点到最远的地点和最近的地点的距离差最小。iPig现在想知道这个距离差最小是多少。 由于iPig现在手上没有电脑,所以不能编程解决这个如此简单的问题,所以他马上打了个电话,要求你帮他解决这个问题。iPig告诉了你PKU的n个隐秘地点的坐标,请你编程求出iPig的问题。

    Solution

    枚举一个起始点,在 (kdtree) 上查找离这个点最近的点和最远的点
    (kdtree) 一次查询的期望复杂度是 (O(k*n^{frac{1}{k}}))
    本题可以过

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=500010,inf=1e9;
    int n,D,tmax,tmin,I;
    struct data{
    	int a[2],mn[2],mx[2],l,r;
    	inline int& operator [](int x){return a[x];}
    }t[N];
    inline bool operator <(data p,data q){return p[D]<q[D];}
    inline void upd(int o){
    	int ls=t[o].l,rs=t[o].r;
    	for(int i=0;i<2;i++){
    		t[o].mn[i]=min(t[o].mn[i],min(t[ls].mn[i],t[rs].mn[i]));
    		t[o].mx[i]=max(t[o].mx[i],max(t[ls].mx[i],t[rs].mx[i]));
    	}
    }
    inline int build(int l,int r,int k){
    	D=k;
    	int mid=(l+r)>>1,o=mid;
    	nth_element(t+l,t+mid,t+r+1);
    	for(int i=0;i<2;i++)t[o].mn[i]=t[o].mx[i]=t[o][i];
    	if(l<mid)t[o].l=build(l,mid-1,k^1);
    	if(r>mid)t[o].r=build(mid+1,r,k^1);
    	return upd(o),o;
    }
    inline int cmax(int o){
    	if(!o)return 0;
    	int ret=0;
    	for(int i=0;i<2;i++)
    		ret+=max(abs(t[o].mx[i]-t[I][i]),abs(t[o].mn[i]-t[I][i]));
    	return ret;
    }
    inline int dis(int o){return abs(t[o][0]-t[I][0])+abs(t[o][1]-t[I][1]);}
    inline void qmax(int o){
    	int dl=cmax(t[o].l),dr=cmax(t[o].r),dc=dis(o);
    	tmax=max(tmax,dc);
    	if(dl>dr){
    		if(dl>tmax)qmax(t[o].l);
    		if(dr>tmax)qmax(t[o].r);
    	}
    	else{
    		if(dr>tmax)qmax(t[o].r);
    		if(dl>tmax)qmax(t[o].l);
    	}
    }
    inline int cmin(int o){
    	if(!o)return inf;
    	int ret=0;
    	for(int i=0;i<2;i++)ret+=max(0,t[I][i]-t[o].mx[i]);
    	for(int i=0;i<2;i++)ret+=max(0,t[o].mn[i]-t[I][i]);
    	return ret;
    }
    inline void qmin(int o){
    	if(!o)return ;
    	int dl=cmin(t[o].l),dr=cmin(t[o].r),dc=dis(o);
    	if(dc)tmin=min(tmin,dc);
    	if(dl<dr){
    		if(dl<tmin)qmin(t[o].l);
    		if(dr<tmin)qmin(t[o].r);
    	}
    	else{
    		if(dr<tmin)qmin(t[o].r);
    		if(dl<tmin)qmin(t[o].l);
    	}
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n;
      for(int i=1;i<=n;i++)gi(t[i][0]),gi(t[i][1]);
      for(int i=0;i<=1;i++)t[0].mn[i]=inf,t[0].mx[i]=-inf;
      int rt=build(1,n,0),ans=inf;
      for(int i=1;i<=n;i++){
    	  tmax=0;tmin=inf;I=i;
    	  qmin(rt);qmax(rt);
    	  ans=min(ans,tmax-tmin);
      }
      cout<<ans<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    js基础
    linux 权限计算
    postman 测试http post的json请求
    Crontab 让linux定时执行shell脚本
    Java:扫描包含图片的文件夹,将符合分辨率格式的复制出来
    php引用其他目录的php文件
    电脑屏幕动图制作之-----GifCam
    通过Excel表创建sql脚本
    通过Navicat将Excel表中的数据导入到数据库
    需求设计之初造火箭?
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9041728.html
Copyright © 2011-2022 走看看