BZOJ 4520 [Cqoi2016]K远点对(KD-tree+堆)

6 篇文章 0 订阅
3 篇文章 0 订阅

不要学我的KD-Tree,很不标准,只是不知道为什么把题水过了。

话说这个BZOJ真的不行啊,怀疑跟少主家是一样的评测机,哼~。

题意

已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对。
k<=100

分析

既然答案只有一个的话。。。
我想的话是二分猜+KD-tree
时间复杂度大概是60*n*n^1/2

等等。。。K怎么这么小

比K大的就搜索,否则不搜索。。。

优先队列吧

如果按照加点的话很可能不平衡,因此不如先加进去。自己这个点应该不会造成影响,出题人良心(大拇指

可是会有重复点啊,那么我们维护大小为2k的?应该可行

最后我们的点按照横坐标排序,然后最左,最右这种操作来搜索。
哇哈哈哈,试试

注意开LL

时间复杂度大概就是n^3/2这个级别的吧
.
.
.
.
.
.
.
事实证明我yy的那个左右加点的操作是把时间拖慢了,KDtree本来自带一个排序嘛。。。
(还有其实这根本不是我认真写的思路,是我写给自己看的思考过程而已啦哈哈哈哈)

代码

先写几个KDtree注意的点
1、mx和mi两个在估价的时候同时要用,不要以为找最大值就不用mi了,可能负数呢,所以不要忘了abs。
2、D那个排序的全局变量只能放在结构体外面,因为结构体内部的东西不一定被定义了的。
3、特别注意估价函数以及查询的写法,KD-tree的核心了吧。

using namespace std;
typedef long long LL;
const int maxn=2e5+1000,inf=2147483647;
struct Point{
    int d[2];
    friend bool operator<(Point a,Point b)
    {
        return a.d[0]!=b.d[0]?a.d[0]<b.d[0]:a.d[1]<b.d[1];
    }
    void ins()
    {
        scanf("%d%d",&d[0],&d[1]);
    }
}p[maxn];
struct mycmp
{
    bool operator()(LL a,LL b)
    {
        return a>b;
    }
};
priority_queue<LL,vector<LL>,mycmp>pq;
int D;
bool cmp(Point a,Point b)
{
    return a.d[D]<b.d[D];
}
int n,k;
struct KD_Tree
{
    static const int K=2;
    int np,rt;
    struct data
    {
        int mi[K],mx[K],ch[2];
    }T[maxn];
    void Intial()
    {
        np=rt=0;
        memset(T,0,sizeof(T));
    }
    void pushup(int now)
    {
        for(int i=0;i<K;i++)
        {
            T[now].mi[i]=inf,T[now].mx[i]=0;
            for(int j=0;j<2;j++)
            {
                if(T[now].ch[j])
                {
                    T[now].mi[i]=min(T[now].mi[i],T[T[now].ch[j]].mi[i]);
                    T[now].mx[i]=max(T[now].mx[i],T[T[now].ch[j]].mx[i]);
                }   
            }
        }
    }
    void Build(int &now,int L,int R,int k)
    {
        now=++np;
        int m=(L+R)>>1;
        if(L==R)
        {
            for(int i=0;i<K;i++)
                T[now].mx[i]=T[now].mi[i]=p[L].d[i];
            return;
        }
        D=k;nth_element(p+L,p+m+1,p+R+1,cmp);
        Build(T[now].ch[0],L,m,(k+1)%K);
        Build(T[now].ch[1],m+1,R,(k+1)%K);
        pushup(now);
    }
    LL Dist(data a,Point b)
    {
        LL ret=0;
        int t;
        for(int i=0;i<K;i++)
            t=max( abs(a.mx[i]-b.d[i]) , abs(a.mi[i]-b.d[i]) ),ret+=1ll*t*t;
        return ret;
    }
    void query(int now,int L,int R,Point a)
    {
        if(L==R)
        {
            LL d=Dist(T[now],a);
            if(pq.size()<2*k)pq.push(d);
            else if(d>pq.top())pq.pop(),pq.push(d);
            return;
        }
        int m=(L+R)>>1;
        LL d1=Dist(T[T[now].ch[0]],a),d2=Dist(T[T[now].ch[1]],a);
        if(d1>d2)
        {
            if(pq.size()<2*k || d1>pq.top())query(T[now].ch[0],L,m,a);
            if(pq.size()<2*k || d2>pq.top())query(T[now].ch[1],m+1,R,a);
        }
        else
        {
            if(pq.size()<2*k || d2>pq.top())query(T[now].ch[1],m+1,R,a);
            if(pq.size()<2*k || d1>pq.top())query(T[now].ch[0],L,m,a);
        }
    }
}kdt;
void Init()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)p[i].ins();//,pp[i]=p[i];
    kdt.Build(kdt.rt,1,n,0);
}
void solve()
{
    /*sort(pp+1,pp+n+1);
    for(int i=1,j=n;i<=j;i++,j--)
    {
        kdt.query(kdt.rt,1,n,pp[i]);
        if(i!=j)kdt.query(kdt.rt,1,n,pp[j]);
    }*/
    for(int i=1;i<=n;i++)
        kdt.query(kdt.rt,1,n,p[i]);
    //printf("%lld\n",pq.top());
    cout<<pq.top()<<endl;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out1.txt","w",stdout);
    Init();
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值