码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】[SDOI2010]捉迷藏

时间:2019-12-07 23:20:47      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:应该   最大和   sdoi   显示   max   names   mat   using   最大值   

题目链接:https://www.luogu.com.cn/problem/P2479

题目大意:求平面\(n\)个点中,到其它\(n-1\)个点的曼哈顿距离最大和最小距离之差最小的点,求出这个这个距离差。

\(K-D-Tree\)维护区间,剪枝搜索。

值得一提的是,对于\(maxdis\)的查询还是比较显然的,找到它到当前点所维护区间的端点的距离的最大值即可。对于最小距离……还是(对我来说)有点坑的。

首先,判断最小距离的时候,当这个点在当前询问区间的话,它的距离显示为0,就炸了qwq,所以,求完这个距离,我们更新答案的时候应该判断是否是真的这个距离,即为零不更新。

那么其它的都和\(k\)远点对差不多,没有重构,没有替罪羊

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN=5e5+10;
#define inf 2147483647
struct pt{
    int x[2];
}p[MAXN];
int rt,D,tot,n,ans,ans1,ans2;
int ls[MAXN],rs[MAXN];
struct node{
    int mi[2],mx[2],siz;
    pt c;
}tr[MAXN];
inline void pushup(int x){
    int l=ls[x],r=rs[x];
    tr[x].siz=tr[l].siz+tr[r].siz+1;
    for(int i=0;i<=1;++i){
        tr[x].mi[i]=tr[x].mx[i]=tr[x].c.x[i];
        if(l)tr[x].mi[i]=min(tr[x].mi[i],tr[l].mi[i]),tr[x].mx[i]=max(tr[x].mx[i],tr[l].mx[i]);
        if(r)tr[x].mi[i]=min(tr[x].mi[i],tr[r].mi[i]),tr[x].mx[i]=max(tr[x].mx[i],tr[r].mx[i]);
    }
}
int operator<(pt a,pt b){return a.x[D]<b.x[D];}
int build(int l,int r,int d){
    if(l>r)return 0;
    int x=++tot,mid=l+r>>1;
    D=d;nth_element(p+l,p+mid,p+r+1);
    tr[x].c=p[mid];ls[x]=build(l,mid-1,d^1);
    rs[x]=build(mid+1,r,d^1);pushup(x);return x;
}
inline int abs(int x){return x<0?-x:x;}
inline int Get(pt x,pt y){return abs(x.x[0]-y.x[0])+abs(x.x[1]-y.x[1]);}
int Getdis(int x,pt a){
    int res=0;
    for(int i=0;i<=1;++i){
        res+=max(0,a.x[i]-tr[x].mx[i])+max(0,tr[x].mi[i]-a.x[i]);
    }
    return res;//min
}
int getdis(int x,pt a){
    int res=0;
    for(int i=0;i<=1;++i)res+=max(abs(tr[x].mi[i]-a.x[i]),abs(tr[x].mx[i]-a.x[i]));
    return res;//max
}
void querymax(int x,pt y){
    ans2=max(ans2,Get(tr[x].c,y));
    int l=ls[x],r=rs[x],dl,dr;
    dl=l?getdis(l,y):-inf;
    dr=r?getdis(r,y):-inf;
    if(dl>dr){
        if(dl>ans2)querymax(l,y);
        if(dr>ans2)querymax(r,y);
    }
    else{
        if(dr>ans2)querymax(r,y);
        if(dl>ans2)querymax(l,y);
    }
}
void querymin(int x,pt y){
    int tmp=Get(tr[x].c,y);
    if(tmp)ans1=min(ans1,tmp);
    int l=ls[x],r=rs[x],dl,dr;
    dl=l?Getdis(l,y):inf;
    dr=r?Getdis(r,y):inf;
    if(dl<dr){
        if(dl<ans1)querymin(l,y);
        if(dr<ans1)querymin(r,y);
    }
    else{
        if(dr<ans1)querymin(r,y);
        if(dl<ans1)querymin(l,y);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x[0],&p[i].x[1]);
    rt=build(1,n,0);ans=inf;
    for(int i=1;i<=n;++i){
        ans1=inf,ans2=-inf;
        querymax(rt,p[i]);
        querymin(rt,p[i]);
        ans=min(ans,ans2-ans1);
        //cout<<"Casepoint"<<i<<":"<<ans<<" "<<ans2<<" "<<ans1<<endl;
    }
    printf("%d\n",ans);
    return 0;
}

【题解】[SDOI2010]捉迷藏

标签:应该   最大和   sdoi   显示   max   names   mat   using   最大值   

原文地址:https://www.cnblogs.com/h-lka/p/12003727.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!