• 洛谷4631 [APIO2018] Circle selection 选圆圈 (KD树)


    qwq纪念AC450

    一开始想这个题想复杂了。

    首先,正解的做法是比较麻烦的。
    qwqq
    那么就不如来一点暴力的东西,看到平面上点的距离的题,不难想到(KD-Tree)

    我们用类似平面最近点对那个题一样的维护方式,对于一个子树内部,分别维护每一个维度的最大值和最小值,还有半径的最大值。

    然后(sort)一遍,从半径大到小依次(query),每次(query)的时候,对于当前点,合法的条件是他和目标点的距离要小于等于两个圆的半径的和。

    那么对于子树的估价函数,我们默认如果当前目标点的当前维度的范围是(mn-mx)之间的话,距离就是(0),否则取一个最短距离,然后和上述要求一样的比较方式。进行剪枝。

    这样就能直接通过洛谷的数据了,但是由于(loj)的数据比较强,所以还需要将原来的点绕着一个点旋转一下。

    那么假设我们旋转的角度是(phi)

    那么我们需要将原来那两个坐标乘上一个矩阵

    cos -sin
    sin cos
    

    直接上代码了

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<set>
    #define pb push_back
    #define mk make_pair
    #define ll long long
    #define lson ch[x][0]
    #define rson ch[x][1]
    #define double long double
    #define int long long
    
    using namespace std;
    
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 4e5+1e2;
    const double phi = 1.04719755116;
    const double eps = 1e-4;
    
    struct KD{
    	double d[2],mx[2],mn[2];
    	double bj,mr;
    	int l,r;
    	int num;
    };
    
    KD now,t[maxn];
    int root,ymh,n,m;
    int ans[maxn];
    
    struct Node{
      double x,y;
      double r;
      int num;
    };
    
    Node a[maxn];
    
    bool cmp(Node a,Node b)
    {
    	if (a.r==b.r) return a.num<b.num;
    	return a.r>b.r;
    }
    
    bool operator <(KD a,KD b)
    {
    	return a.d[ymh]<b.d[ymh];
    }
    
    void up(int root)
    {
    	for (int i=0;i<=1;i++)
    	{
    		if (t[root].l) t[root].mn[i]=min(t[root].mn[i],t[t[root].l].mn[i]);
    		if (t[root].l) t[root].mx[i]=max(t[root].mx[i],t[t[root].l].mx[i]);
    		if (t[root].l) t[root].mr=max(t[root].mr,t[t[root].l].mr);
    		if (t[root].r) t[root].mr=max(t[root].mr,t[t[root].r].mr);
    		if (t[root].r) t[root].mn[i]=min(t[root].mn[i],t[t[root].r].mn[i]);
    		if (t[root].r) t[root].mx[i]=max(t[root].mx[i],t[t[root].r].mx[i]);
    	}
    }
    
    void build(int &x,int l,int r,int dd)
    {
    	ymh = dd;
    	int mid = l+r >> 1;
    	x=mid;
    	nth_element(t+l,t+mid,t+r+1);
    	for (int i=0;i<=1;i++) t[x].mn[i]=t[x].mx[i]=t[x].d[i];
    	t[x].mr=t[x].bj;
    	if (l<x) build(t[x].l,l,mid-1,dd^1);
    	if (x<r) build(t[x].r,mid+1,r,dd^1);
    	up(x);
    }
    
    inline double getdis(int x)
    {
    	double ans=0;
    	for (int i=0;i<=1;i++) ans=ans+(t[x].d[i]-now.d[i])*(t[x].d[i]-now.d[i]);
    	return ans;
    }
    
    inline double calc(int x)
    {
    	double ans=0;
    	for (int i=0;i<=1;i++) 
    	{
    	  double tmp=0;
    	  if (now.d[i]>=t[x].mn[i] && now.d[i]<=t[x].mx[i]) tmp=0;
    	  else tmp=min((t[x].mn[i]-now.d[i])*(t[x].mn[i]-now.d[i]),(t[x].mx[i]-now.d[i])*(t[x].mx[i]-now.d[i]));
    	  ans=ans+tmp;
        }
    	return ans;
    }
    
    void query(int x)
    {
    	//cout<<now.num<<endl;
    	//cout<<x<<" "<<t[x].l<<" "<<t[x].r<<" "<<t[x].mr<<" "<<t[x].d[1]<<endl;;
    	if (!x) return;
    	double d = getdis(x);
    	double d1 = calc(t[x].l);
    	double d2 = calc(t[x].r);
    	//cout<<d1<<" "<<(t[t[x].l].mr+now.bj)<<" "<<d2<<endl;
    	if (!ans[t[x].num] && (t[x].bj+now.bj)*(t[x].bj+now.bj)-d>=-eps) ans[t[x].num]=now.num;
    	if ((t[t[x].l].mr+now.bj)*(t[t[x].l].mr+now.bj)-d1>=-eps) query(t[x].l);
    	if ((t[t[x].r].mr+now.bj)*(t[t[x].r].mr+now.bj)-d2>=-eps) query(t[x].r);
    }
    
    
    signed main()
    {
      n=read();
      for (int i=1;i<=n;i++)
      {
      	 double x=read(),y=read(),r=read();
      	 double tmp = x;
    	 x=cos(phi)*x-sin(phi)*y;
    	 y=sin(phi)*tmp+cos(phi)*y;
    	 t[i].num=i;
    	 t[i].d[0]=x;
    	 t[i].d[1]=y;
    	 t[i].bj=r;
    	 a[i].x=x;
    	 a[i].y=y;
    	 a[i].num=i;
    	 a[i].r=r; 
    	 //printf("%.2lf %.2lf %.2lf
    ",x,y,r);
    	 //cout<<endl;
      }
      build(root,1,n,0);
      //cout<<"********"<<endl;
      sort(a+1,a+1+n,cmp);
      for (int i=1;i<=n;i++)
      {
      	 if (ans[a[i].num]) continue;
      	 now.d[0]=a[i].x;
      	 now.d[1]=a[i].y;
      	 now.bj=a[i].r;
      	 now.num=a[i].num;
      	 query(root);
      	 //out<<"*******"<<endl;
      }
      for (int i=1;i<=n;i++) cout<<ans[i]<<" ";
      return 0;
    }
    
    
  • 相关阅读:
    Delphi 实现C语言函数调用
    Delphi采用接口实现DLL调用
    select、poll、epoll之间的区别总结[整理]
    int 的重载
    qt 安装包生成2
    线程池的简单实现
    qt 安装包生成
    linux 下tftpf搭建
    2018C语言助教总结
    动态规划——最长子序列长度
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10297196.html
Copyright © 2020-2023  润新知