bzoj2564集合的面积

题目描述

  对于一个平面上点的集合P={(xi,yi )},定义集合P的面积F(P)为点集P的凸包的面积。
  对于两个点集A和B,定义集合的和为:
  A+B={(xiA+xjB,yiA+yjB ):(xiA,yiA )∈A,(xjB,yjB )∈B}
  现在给定一个N个点的集合A和一个M个点的集合B,求2F(A+B)。

 


输入格式

 第一行包含用空格隔开的两个整数,分别为N和M;
  第二行包含N个不同的数对,表示A集合中的N个点的坐标;
  第三行包含M个不同的数对,表示B集合中的M个点的坐标。

 

输出格式

 一共输出一行一个整数,2F(A+B)。


 

数据规模和约定
  对于30%的数据满足N ≤ 200,M ≤ 200;
  对于100%的数据满足N ≤ 10^5,M ≤ 10^5,|xi|, |yi| ≤ 10^8。

  • 题解:

    • 如果一个点成为了和$A+B$的凸包,那么一定同时在$A$和$B$的凸包上;
    • 设$A+B$看成把凸包$A$平移后放在凸包$B$上,发现在两个凸包上组合成新的凸包的点对是单调的;
    • 类似$graham$维护两个指针;
    • 不太好说,附图,但是建议自己$YY$:

       

    •  1 #include<bits/stdc++.h>
       2 #define ll long long 
       3 using namespace std;
       4 const int N=200010;
       5 int n,m,cnt1,cnt2,Cnt;
       6 char gc(){
       7     static char*p1,*p2,s[1000000];
       8     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
       9     return (p1==p2)?EOF:*p1++;
      10 }
      11 int rd(){
      12     int x=0,f=1; char c=gc();
      13     while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
      14     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=gc();}
      15     return x*f;
      16 }
      17 struct poi{
      18     int x,y;
      19     poi(int _x=0,int _y=0):x(_x),y(_y){};
      20     poi operator +(const poi&A)const{return poi(x+A.x,y+A.y);}
      21     poi operator -(const poi&A)const{return poi(x-A.x,y-A.y);}
      22     bool operator <(const poi&A)const{return x==A.x?y<A.y:x<A.x;}
      23 }p1[N],p2[N],q1[N],q2[N],Q[N];
      24 ll crs(poi A,poi B){return (ll)A.x*B.y-(ll)A.y*B.x;}
      25 void convex(poi *p,poi *q,int&tot,int&cnt){
      26     if(tot==1){q[cnt=1]=q[2]=p[1];return;}
      27     sort(p+1,p+tot+1);
      28     q[cnt=1]=p[1];
      29     for(int i=2;i<=tot;i++){
      30         while(cnt>1 && crs(q[cnt]-q[cnt-1],p[i]-q[cnt])<=0)cnt--;
      31         q[++cnt]=p[i];
      32     }
      33     int now=cnt;
      34     for(int i=tot-1;i;i--){
      35         while(cnt>now && crs(q[cnt]-q[cnt-1],p[i]-q[cnt])<=0)cnt--;
      36         q[++cnt]=p[i];
      37     }
      38     cnt--;
      39 }
      40 int main(){
      41     #ifndef ONLINE_JUDGE
      42     freopen("bzoj2564.in","r",stdin);
      43     freopen("bzoj2564.out","w",stdout);
      44     #endif
      45     n=rd();m=rd();
      46     for(int i=1;i<=n;i++)p1[i].x=rd(),p1[i].y=rd();
      47     for(int i=1;i<=m;i++)p2[i].x=rd(),p2[i].y=rd();
      48     convex(p1,q1,n,cnt1);
      49     convex(p2,q2,m,cnt2);
      50     int i,j;
      51     for(i=1,j=1;i<=cnt1;i++){
      52         Q[++Cnt]=q1[i]+q2[j];
      53         while(j<=cnt2&&crs(q2[j+1]-q2[j],q1[i+1]-q1[i])>0){
      54             Q[++Cnt]=q1[i]+q2[++j];
      55         }
      56     }
      57     for(;j<=cnt2+1;j++)Q[++Cnt]=q1[i]+q2[j];
      58     Cnt--;
      59     ll ans=0;
      60     for(i=2;i<Cnt;i++)ans += crs(Q[i]-Q[1],Q[i+1]-Q[1]);
      61     printf("%lld\n",ans);
      62     return 0;
      63 }
      bzoj2564

       

 

转载于:https://www.cnblogs.com/Paul-Guderian/p/10269970.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值