zoukankan      html  css  js  c++  java
  • bzoj1941[Sdoi2010]Hide and Seek

    bzoj1941[Sdoi2010]Hide and Seek

    题意:

    平面上n个点,求一个点使得离它最近的点和最远的点离它的曼哈顿距离差最小(若选的点处已有点,则改点不算)。n≤500000

    题解:

    第一次写kd树,感觉眼睛又瞎了(玄学复杂度)。首先先把所有点横坐标和纵坐标轮流为关键字排序建一个平衡树,维护每棵子树里的横纵坐标最大最小值。在树上查询时就启发式搜索,比如说正在查询里某点最远的点,则如果当前子树的横纵坐标最大最小值与某点的曼哈顿距离小于答案,就返回,否则对左右子树估价,那边越可能得到最优解就先往哪边走。这么暴力的操作,却可以证明,单次查询均摊复杂度为O(sqrt(n))。好神奇(不过常数应该不小)。

    对应于本题,先将所有点建成kd树,然后有奇怪性质:所求点一定是这些点中的一个,所以枚举所有点,查询离这个点最远最近的点的与它的曼哈顿距离差,寻找最小的一个输出。估价函数具体见代码,注意求最远点和求最近点的估价函数不一样。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define inc(i,j,k) for(int i=j;i<=k;i++)
     5 #define maxn 500010
     6 #define INF 0x3fffffff
     7 using namespace std;
     8 
     9 inline int read(){
    10     char ch=getchar(); int f=1,x=0;
    11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    12     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    13     return f*x;
    14 }
    15 int n,f,rt,mxans,mnans;
    16 struct p{int pos[2]; bool operator < (const p &a)const{return pos[f]<a.pos[f];}}ps[maxn];
    17 struct nd{p pos; int mx[2],mn[2],lc,rc;}nds[maxn];
    18 int dis(p a,p b){return abs(a.pos[0]-b.pos[0])+abs(a.pos[1]-b.pos[1]);}
    19 void update(int x){
    20     inc(i,0,1){
    21         if(nds[x].lc)
    22             nds[x].mx[i]=max(nds[x].mx[i],nds[nds[x].lc].mx[i]),
    23             nds[x].mn[i]=min(nds[x].mn[i],nds[nds[x].lc].mn[i]);
    24         if(nds[x].rc)
    25             nds[x].mx[i]=max(nds[x].mx[i],nds[nds[x].rc].mx[i]),
    26             nds[x].mn[i]=min(nds[x].mn[i],nds[nds[x].rc].mn[i]);
    27     }
    28 }
    29 int build(int l,int r,int now){
    30     f=now; int mid=(l+r)>>1; nth_element(ps+l,ps+mid,ps+r+1);
    31     inc(i,0,1)nds[mid].mx[i]=nds[mid].mn[i]=ps[mid].pos[i]; nds[mid].pos=ps[mid];
    32     if(l<mid)nds[mid].lc=build(l,mid-1,now^1); if(mid<r)nds[mid].rc=build(mid+1,r,now^1);
    33     update(mid); return mid;
    34 }
    35 int getmax(int x,p a){
    36     int q=0; inc(i,0,1)q+=max(abs(a.pos[i]-nds[x].mx[i]),abs(a.pos[i]-nds[x].mn[i])); return q;
    37 }
    38 int getmin(int x,p a){
    39     int q=0; inc(i,0,1)q+=max(a.pos[i]-nds[x].mx[i],0),q+=max(nds[x].mn[i]-a.pos[i],0); return q;
    40 }
    41 void querymax(int x,p a){
    42     mxans=max(mxans,dis(a,nds[x].pos)); int dl=0,dr=0;
    43     if(nds[x].lc)dl=getmax(nds[x].lc,a); if(nds[x].rc)dr=getmax(nds[x].rc,a);
    44     if(dl>dr){
    45         if(mxans<dl)querymax(nds[x].lc,a); if(mxans<dr)querymax(nds[x].rc,a);
    46     }else{
    47         if(mxans<dr)querymax(nds[x].rc,a); if(mxans<dl)querymax(nds[x].lc,a);
    48     }
    49 }
    50 void querymin(int x,p a){
    51     if(dis(a,nds[x].pos))mnans=min(mnans,dis(a,nds[x].pos)); int dl=INF,dr=INF;
    52     if(nds[x].lc)dl=getmin(nds[x].lc,a); if(nds[x].rc)dr=getmin(nds[x].rc,a);
    53     if(dl<dr){
    54         if(mnans>dl)querymin(nds[x].lc,a); if(mnans>dr)querymin(nds[x].rc,a);
    55     }else{
    56         if(mnans>dr)querymin(nds[x].rc,a); if(mnans>dl)querymin(nds[x].lc,a);
    57     }
    58 }
    59 int query(p a){
    60     mxans=0; querymax(rt,a); mnans=INF; querymin(rt,a); return mxans-mnans;
    61 }
    62 int main(){
    63     n=read(); inc(i,1,n)ps[i].pos[0]=read(),ps[i].pos[1]=read(); rt=build(1,n,0);
    64     int ans=INF; inc(i,1,n)ans=min(ans,query(ps[i])); printf("%d",ans); return 0;
    65 }

     

    20160906

  • 相关阅读:
    html的转码玉反转码
    获取url据对路径写法
    CSS 外边距合并
    页面禁制选中元素的 背景变蓝的通用写法
    centos7.3上安装oracle11.2.4RAC
    通过ansible检查所有服务器根目录磁盘使用情况
    解决es集群启动完成后报master_not_discovered_exception(hostname有错误)
    tidb4.0执行大型sql报没有tmp目录错处理(ERROR 1105 (HY000): open /tmp/1000_tidb/MC4wLjAuMDo0MDAwLzAuMC4wLjA6MTAwODA)
    aix磁盘创建pv、lv
    aix6.1安装oracle
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5861859.html
Copyright © 2011-2022 走看看