• bzoj4520【cqoi2016】K远点对


    题目描述

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


    输入格式

    输入文件第一行为用空格隔开的两个整数 N, K。接下来 N 行,每行两个整数 X,Y,表示一个点
    的坐标。1 < =  N < =  100000, 1 < =  K < =  100, K < =  N*(N−1)/2 , 0 < =  X, Y < 2^31。

    输出格式

    输出文件第一行为一个整数,表示第 K 远点对的距离的平方(一定是个整数)。


    • 题解:

      • 注意只需要保证最大的k个值都被找到就可以确定答案了;
      • 旋转卡壳做法:
      • 平面最近点对可以通过求出凸包之后(特判一下一条直线)卡壳得到;
      • 这样求$min(n-1,k)$次最远点对;
      • 每求一次,就将求出的点对删掉,将和它们相关的距离放进小顶堆中,多于$k$个就丢掉最小值;
      • 答案就是堆顶;
      • 当做到最远距离已经<=堆顶时就可以break了;
      • 复杂度:$O(NlogN+NKlogK)$
    •  1 #include<bits/stdc++.h>
       2 #define ll long long 
       3 using namespace std;
       4 const int N=100010; 
       5 int n,m,WD,mn[N][2],mx[N][2],ch[N][2],rt;
       6 struct P{
       7     int x,y;
       8     P(int _x=0,int _y=0):x(_x),y(_y){};
       9     P operator -(const P&a)const{return P(x-a.x,y-a.y);}
      10     bool operator <(const P&a)const{return WD?y<a.y:x<a.x;}
      11 }p[N],q;
      12 priority_queue<ll,vector<ll>,greater<ll> >ans;
      13 ll len(P a){return (ll)a.x*a.x+(ll)a.y*a.y;} 
      14 void build(int&k,int l,int r,int d){
      15     k=(l+r)>>1;
      16     WD=d;nth_element(p+l,p+k,p+r+1);
      17     mn[k][0]=mx[k][0]=p[k].x;
      18     mn[k][1]=mx[k][1]=p[k].y;
      19     if(l<k){build(ch[k][0],l,k-1,d^1);}
      20     if(k<r){build(ch[k][1],k+1,r,d^1);}
      21     for(int i=0;i<2;++i)if(ch[k][i]){
      22         int t = ch[k][i];
      23         mn[k][0]=min(mn[t][0],mn[k][0]);
      24         mn[k][1]=min(mn[t][1],mn[k][1]);
      25         mx[k][0]=max(mx[t][0],mx[k][0]);
      26         mx[k][1]=max(mx[t][1],mx[k][1]);
      27     }
      28 }
      29 inline ll sqr(int x){return (ll)x*x;}
      30 inline ll cal(int k){
      31     if(!k)return 0;
      32     return max(sqr(q.x-mn[k][0]),sqr(q.x-mx[k][0])) + max(sqr(q.y-mn[k][1]),sqr(q.y-mx[k][1])) ;
      33 }
      34 void query(int k){
      35     ll tmp = len(p[k]-q);
      36 //    printf("%lld
      ",tmp);
      37     if(tmp>ans.top())ans.pop(),ans.push(tmp);
      38     ll tl = cal(ch[k][0]), tr = cal(ch[k][1]);
      39     if(tl>tr){
      40         if(tl>ans.top())query(ch[k][0]);
      41         if(tr>ans.top())query(ch[k][1]);
      42     }else{
      43         if(tr>ans.top())query(ch[k][1]);
      44         if(tl>ans.top())query(ch[k][0]);
      45     }
      46 }
      47 int main(){
      48     #ifndef ONLINE_JUDGE
      49     freopen("T2.in","r",stdin);
      50     freopen("T2.out","w",stdout);
      51     #endif
      52     scanf("%d%d",&n,&m);
      53     for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y);
      54     for(int i=1;i<=m*2;++i)ans.push(0);
      55     build(rt,1,n,0);
      56     for(int i=1;i<=n;++i){q=p[i];query(rt);}
      57     cout<<ans.top()<<endl;
      58     return 0;
      59 }
      bzoj4520(kdt)

      • $k-d tree$做法
      • 同样$k-d$可以支持查找最远点对,精髓在于$kdtree$估价函数的剪枝;
      • 对每个点找一次最远点对,同样放进小顶堆维护;
      • 如果堆大小达到$2*k$(因为此时的点对有序);
      • 答案就是堆顶;
      • 同样<=堆顶的值就对答案无影响了,直接用$kdtree$的估值函数减掉;
      • 复杂度似乎比较玄。。。$O(Nsqrt{N} + Nsqrt{N}logK)$
    •  1 #include<bits/stdc++.h>
       2 #define ll long long
       3 using namespace std;
       4 const int N=100010;
       5 int n,k,vis[N],id[N];
       6 priority_queue<ll,vector<ll>,greater<ll> >ans;
       7 char gc(){
       8     static char*p1,*p2,s[1000000];
       9     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
      10     return(p1==p2)?EOF:*p1++;
      11 } 
      12 int rd(){
      13     int x=0; char c=gc();
      14     while(c<'0'||c>'9')c=gc();
      15     while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
      16     return x;
      17 }
      18 struct P{
      19     int x,y;
      20     P(int _x=0,int _y=0):x(_x),y(_y){};
      21     P operator -(const P&a)const{return P(x-a.x,y-a.y);}
      22     bool operator <(const P&a)const{return x==a.x?y<a.y:x<a.x;}
      23 }p[N],q[N];
      24 inline ll len(P a){return (ll)a.x*a.x+(ll)a.y*a.y;}
      25 inline ll crs(P a,P b){return (ll)a.x*b.y-(ll)a.y*b.x;}
      26 void ins(ll x){
      27     if((int)ans.size()<k)ans.push(x);
      28     else {
      29         if(x<=ans.top())return;    
      30         ans.pop();ans.push(x);
      31     }
      32 }
      33 bool solve(){
      34     int top=1,i;
      35     i=1;while(vis[i])++i;
      36     q[top=1]=p[i];id[top]=i;
      37     for(++i;i<=n;++i)if(!vis[i]){
      38         while(top>1&&crs(q[top]-q[top-1],p[i]-q[top])<=0)top--;
      39         q[++top]=p[i],id[top]=i;
      40     }
      41     int now=top;
      42     i=n;while(vis[i])--i;
      43     for(--i;i;--i)if(!vis[i]){
      44         while(top>now&&crs(q[top]-q[top-1],p[i]-q[top])<=0)top--;
      45         q[++top]=p[i],id[top]=i;
      46     }
      47     top--;
      48     if(top==2){
      49         vis[id[1]]=vis[id[2]]=1;
      50         ins(len(q[1]-q[2]));
      51     } 
      52     int x = 2;ll mx=-1,pos1,pos2;
      53     for(i=1;i<=top;++i){
      54         P A = q[i%top+1]-q[i];
      55         while(x!=i&&crs(A,q[x%top+1]-q[x])>0)x=x%top+1;
      56         ll t = len(q[x]-q[i]);
      57         if(t>mx)mx=t,pos1=id[i],pos2=id[x];
      58     }
      59     if(len(p[pos1]-p[pos2])<=ans.top())return false;
      60     for(i=1;i<=n;++i)if(!vis[i]&&i!=pos1){
      61         ins(len(p[i]-p[pos1]));
      62     }
      63     for(i=1;i<=n;++i)if(!vis[i]&&i!=pos1&&i!=pos2){
      64         ins(len(p[i]-p[pos2]));
      65     }
      66     vis[pos1]=vis[pos2]=1;
      67     return true;
      68 }
      69 int main(){
      70     freopen("T2.in","r",stdin);
      71     freopen("T2.out","w",stdout);
      72     n=rd(),k=rd();
      73     for(int i=1;i<=n;++i)p[i].x=rd(),p[i].y=rd();
      74     sort(p+1,p+n+1);
      75     for(int i=1;i<=k;++i)ans.push(0);
      76     for(int i=1;i<=min(k,n-1);++i)if(!solve())break;
      77     cout<<ans.top()<<endl;
      78     return 0;
      79 }
      bzoj4520(旋卡)
  • 相关阅读:
    【git hub使用】
    【struct2 第一天】
    【JSP基础 第一天】
    【Java基础学习 day01】
    网站建设 【Django】 【MTV】
    Python-Json字符串和XML解析
    Python-冒泡和快排
    Python-面向对象编程
    练习-字符串编码
    练习-统计文件中单词数量
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10306228.html
Copyright © 2020-2023  润新知