2983. 玩具

题目链接

2983. 玩具
计算玩具收纳盒中,每个分区内的玩具数量。

约翰的父母有一个烦恼----约翰每次玩完玩具以后总会将玩具乱扔。

他们为约翰准备了一个长方形的玩具收纳盒,用来放他的玩具。

但是约翰非常调皮,每次都非常随意的将玩具扔进盒子中,使得所有玩具都随意混在一起,这让约翰难以找到他喜欢的玩具。

对此,约翰的父母想出了一个对策,用若干个纸板将收纳盒分隔成若干个分区,这样至少扔到不同分区的玩具之间还是能分开的。

下面是一个收纳盒的俯视图示例。

image

你的任务是,每当约翰将玩具扔进收纳盒中时,确定每个分区中有多少个玩具。

输入格式

本题包含多组测试数据。

对于每组数据,第一行包含 \(6\) 个整数 \(n,m,x_1,y_1,x_2,y_2\),表示共有 \(n\) 个纸板,\(m\) 个玩具,收纳盒的左上角坐标为 \((x_1,y_1)\),右下角坐标为 \((x_2,y_2)\)

接下来 \(n\) 行,每行包含两个整数 \(U_i,L_i\),表示第 \(i\) 个纸板的两端点坐标分别为 \((U_i,y_1)\)\((L_i,y_2)\)。数据保证纸板之间不相交,且按照从左至右顺序依次给出。

接下来 \(m\) 行,每行包含两个整数 \(X_j,Y_j\),表示第 \(j\) 个玩具的位置坐标。玩具的给出顺序是随机的。数据保证玩具不会恰好落在纸板上,也不会落在盒子外。

输入由包含单个 \(0\) 的一行结束。

输出格式

对于每组数据,输出 \(n+1\) 行。

\(n\) 个纸板将收纳盒划分为了 \(n+1\) 个分区,从左到右编号为 \(0\sim n\)

按照分区编号从小到大的顺序,每行输出一行信息 \(i: j\),其中 \(i\) 表示分区编号,\(j\) 表示分区内玩具数量。

每组数据之间,用空行隔开。

数据范围

每个测试点最多包含 \(10\) 组数据。
\(1≤n,m≤5000\),
所有坐标取值范围 \([−10^5,10^5]\)

输入样例:

5 6 0 10 60 0
3 1
4 3
6 8
10 10
15 30
1 5
2 1
2 8
5 5
40 10
7 9
4 10 0 10 100 0
20 20
40 40
60 60
80 80
 5 10
15 10
25 10
35 10
45 10
55 10
65 10
75 10
85 10
95 10
0

输出样例:

0: 2
1: 1
2: 1
3: 1
4: 0
5: 1

0: 2
1: 2
2: 2
3: 2
4: 2

注意
如示例所示,落在盒子边缘的玩具也算在盒子内。

解题思路

二分

本题的关键在于如何判断一个点在向量的左右,判断方法如下:
image
对于一个玩具,其位于所有后面挡板的左侧,所有前面挡板的右侧,满足二分性。即可以二分出该玩具所在编号

  • 时间复杂度:\(O(mlogn)\)

代码

#include<iostream>
#include<cstring>
#define fi first
#define se second
using namespace std;
using LL=long long;
const int N=5010;
typedef pair<LL,LL> pll;
pll a[N],b[N];
int n,m;
LL x1,x2,y1,y2;
int res[N];
LL cross(LL x1,LL y1,LL x2,LL y2)
{
    return x1*y2-x2*y1;
}
LL area(pll a,pll b,pll c)
{
    return cross(b.fi-a.fi,b.se-a.se,c.fi-a.fi,c.se-a.se);
}
int find(LL x,LL y)
{
    int l=0,r=n;
    while(l<r)
    {
        int mid=l+r>>1;
        if(area(b[mid],a[mid],{x,y})>0)r=mid;
        else
            l=mid+1;
    }
    return l;
}
int main()
{
    bool is_first=true;
    while(scanf("%d",&n),n)
    {
        if(!is_first)
            puts("");
        scanf("%d%lld%lld%lld%lld",&m,&x1,&y1,&x2,&y2);
        LL u,l;
        for(int i=0;i<n;i++)
        {
            scanf("%lld%lld",&u,&l);
            a[i]={u,y1},b[i]={l,y2};
        }
        a[n]={x2,y1},b[n]={x2,y2};
        int x,y;
        memset(res,0,sizeof res);
        while(m--)
        {
            scanf("%d%d",&x,&y);
            res[find(x,y)]++;
        }
        for(int i=0;i<=n;i++)printf("%d: %d\n",i,res[i]);
        is_first=false;
    }
    return 0;
}
posted @ 2021-12-10 14:54  zyy2001  阅读(56)  评论(0编辑  收藏  举报