2983. 玩具 _ 计算几何

题意

一个盒子被分成了若干个区域,有m个小球,问每个区域里分别有多少个小球。
数据保证玩具不会恰好落在纸板上,也不会落在盒子外。

思路

如何判断小球是否在一个区域内?
我们发现一个小球在区域x,也就是说所有编号小于x的所有隔板都在小球坐标的左边,所有编号大于x的隔板都在小球坐标的右边。

因此问题就变成了如何判断点在直线的左边或者右边.
而且显然满足二段性,因此我们可以二分求解。

如何判断点在直线的左边或者右边
模板公式,判断叉积正负即可。

image
图片链接

代码


#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int> 
#define x first
#define y second
using namespace std;
const int N = 5010;
int n,m;
pii a[N],b[N];
int ans[N];
int cross(int x1,int y1,int x2,int y2){
  return x1*y2-x2*y1;
}
int area(pii a,pii b,pii c){
  return cross(b.x-a.x,b.y-a.y,c.x-a.x,c.y-a.y);
}

int find(int x,int y){
  int l=0,r=n;
  while(l<r){
    int mid=(l+r)/2;
    if(area(b[mid],a[mid],{x,y})>0) r=mid;
    else l=mid+1;
  }
  return r;
}
void solve(){
  bool is_first=true;
  while(cin>>n && n){
     int x1,y1,x2,y2;cin>>m>>x1>>y1>>x2>>y2;
     for(int i=0;i<n;i++){
      int u,l;cin>>u>>l;
      a[i]={u,y1},b[i]={l,y2};
     }
     a[n]={x2,y1},b[n]={x2,y2};
     if(is_first) is_first=false;
     else puts(" ");
       memset(ans, 0, sizeof ans);
     for(int i=0;i<m;i++){
      int x,y;cin>>x>>y;
      ans[find(x,y)]++;
     }
     for(int i=0;i<=n;i++) cout<<i<<": "<<ans[i]<<endl;
  }
} 

signed main(){
  int t=1;
  // cin>>t;
  while(t--)
  solve();
  return 0;
}
posted @ 2022-09-12 17:25  kingwzun  阅读(31)  评论(0编辑  收藏  举报