题目大意:

给定n段线段 编号为1~n

接下来m个询问 给定一点

输出离该点最近的线段的最小编号(距离相等时取编号小的)

题解

大致就是

1.坐标范围为(0,2^16-1)

将坐标系划分为2^8*2^8的小块 编号为0~2^8-1

判断线段穿过哪些小块 并用had[ i ][  ]保存穿过 i小块 的所有线段的编号

2.当给定一个点时 找到该点所在的小块

因为最近的线段可能不存在与这个小块

所以暴力 该小块 及其 八联通小块(共九个小块)的线段

#1. 这样可以获得坐标(x,y)所在小块的编号

int getS(double x,double y) {
int a=round(x), b=round(y);
return (b>>)*(<<)+(a>>);
}

1.round()是一个四舍五入的取整函数 (需要注意的是6.5时得到7或6的概率各50%)

2.(b>>8) 获得纵向该点所在的层数  *(1<<8) 获得该层第一个的编号

  (a>>8) 获得横向所在的位置 相加就是 其所在小块的编号了

#2. 计算点到线段的距离

// 点a与点b的距离
double lenPP(P a,P b) {
return sqrt( (a-b).dot(a-b) );
}
// 点c到线段ab的距离
double lenPS(P a,P b,P c) {
if(a==b) return lenPP(a,c);
if((b-a).dot(c-a)<) return lenPP(c,a);
else if((b-a).dot(c-b)>) return lenPP(c,b);
else return abs((b-a).det(c-a))/lenPP(b,a);
}

需要分三种情况

1. c的垂足在ab上 // 向量ab与ac 点积=0

  那么算出 向量ab与ac 组成的平行四边形面积

  除以 ab的长度 就可以 得到 c到ab的距离

2. c的垂足在a左侧 // 向量ab与ac 点积<0

  ac的长度就是c到ab的距离

3. c的垂足在b右侧 // 向量ab与bc 点积>0

  bc的长度就是c到ab的距离

/*

这道题虽然没有出现精度问题

但是计算几何题精度要求高时 下面的地方可能会有问题

结构体重载时
bool operator == (P p) {
return x-p.x== && y-p.y==;
}
getDis()中
if(dis-ansd<) ...
else if(dis-ansd== ... ) ...

可以改写为

结构体重载时
bool operator == (P p) {
return abs(x-p.x)<eps && abs(y-p.y)<eps;
}
getDis()中
if(dis-ansd<-eps) ...
else if(abs(dis-ansd)<eps ... ) ...

改写规则为

a<0    ->  a<-eps

a<=0  ->  a<eps

a==0  ->  abs(a)<eps

*/

#include <bits/stdc++.h>
using namespace std; const int N=(<<)+;
const double eps=1e-;
double add(double a,double b) {
if(abs(a+b)<eps*(abs(a)+abs(b))) return ;
return a+b;
}
struct P {
double x,y;
P(){};
P(double _x,double _y):x(_x),y(_y){};
P operator - (P p) {
return P(add(x,-p.x),add(y,-p.y)); }
P operator + (P p) {
return P(add(x,p.x),add(y,p.y)); }
P operator * (double d) {
return P(x*d,y*d); }
P operator / (double d) {
return P(x/d,y/d); }
bool operator == (P p) {
return x-p.x== && y-p.y==; }
double dot (P p) {
return add(x*p.x,y*p.y); }
double det (P p) {
return add(x*p.y,-y*p.x); }
}s[],e[],aim;
int n,m,ansi;
double ansd;
int mov[]={
-(N-),-(N-)-,-(N-)+, // 上 左上 右上
N-,(N-)-,(N-)+,-,, // 下 左下 右下 左 右 中
};
// 点a与点b的距离
double lenPP(P a,P b) {
return sqrt( (a-b).dot(a-b) );
}
// 点c到线段ab的距离
double lenPS(P a,P b,P c) {
if(a==b) return lenPP(a,c);
if((b-a).dot(c-a)<) return lenPP(c,a);
else if((b-a).dot(c-b)>) return lenPP(c,b);
else return abs((b-a).det(c-a))/lenPP(b,a);
}
vector <int> had[N*N];
int getS(double x,double y) {
int a=round(x), b=round(y);
return (b>>)*(<<)+(a>>);
}
void getDis(int S) {
for(int i=;i<had[S].size();i++) {
int j=had[S][i];
double dis=lenPS(s[j],e[j],aim);
if(dis-ansd<) ansd=dis, ansi=j; // 若存在更小的距离
else if(dis-ansd== && j<ansi) ansi=j; // 距离相等 取更小的编号
}
}
int main()
{
while(~scanf("%d%d",&n,&m)) {
for(int i=;i<n;i++) {
scanf("%lf%lf%lf%lf",&s[i].x,&s[i].y,&e[i].x,&e[i].y);
P v=e[i]-s[i]; // v为s[i]到e[i]的方向向量
v=v/(N-); // 得到相对于小块长度的单位向量
int a=-; /// 防止重复保存
for(int j=;j<N;j++) {
P h=s[i]+v*j; // 从 s[i]开始 v方向上 j倍长度 的坐标
int b=getS(h.x,h.y); // 得到所在块
if(b!=a) had[b].push_back(i); // 保存穿过 b小块 的 i线段
a=b;
}
}
while(m--) {
scanf("%lf%lf",&aim.x,&aim.y);
ansd=1e10;
int S=getS(aim.x,aim.y);
for(int i=;i<;i++) { // 九个小块
int t=S+mov[i];
if(t>= && t<N*N) getDis(t);
}
printf("%d\n",ansi+);
}
} return ;
}

2018北京网络赛 G The Mole /// 分块暴力 点线距离的更多相关文章

  1. 2015北京网络赛 J Scores bitset+分块

    2015北京网络赛 J Scores 题意:50000组5维数据,50000个询问,问有多少组每一维都不大于询问的数据 思路:赛时没有思路,后来看解题报告也因为智商太低看了半天看不懂.bitset之前 ...

  2. 2015北京网络赛 G Boxes BFS+打表

    G Boxes 题意:n个位置摆有n个箱子,每次移动只能把相邻的垒起来,且上面的必须小于下面的.求摆成升序需要移动多少步. 思路:这里的n很小,只有7.但是bfs最快的情况需要2s左右,所以就打表了. ...

  3. hihocode 1584 : Bounce (找规律)(2017 北京网络赛G)

    题目链接 比赛时随便找了个规律,然后队友过了.不过那个规律具体细节还挺烦的.刚刚偶然看到Q巨在群里提到的他的一个思路,妙啊,很好理解,而且公式写起来也容易.OrzQ巨 #include<bits ...

  4. 北京网络赛G BOXES 状态压缩+有序BFS+高维数组判重

    #include <bits/stdc++.h> using namespace std; ]; ][]; ][][]; ][][][]; ][][][][]; ][][][][][]; ...

  5. 2015北京网络赛 G题 Boxes bfs

    Boxes Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://hihocoder.com/contest/acmicpc2015beijingonl ...

  6. hdu 5038 (2014北京网络赛G 排序水题)

    题意:有n个数字,带入10000 - (100 - ai) ^ 2公式得到n个数,输出n个数中频率最大的数,如果有并列就按值从小到大都输出输出,如果频率相同的数字是全部的n个数,就输出Bad....题 ...

  7. 2018青岛网络赛G - Couleur 区间上的启发式合并

    题意:给出\(a[1...n]\),共\(n\)次操作,每次删除一个位置\(p_i\)(强制在线),此时区间会变为两个分离的区间,求每次操作的最大区间逆序对 首先要知道必要的工具,按权值建立的主席树可 ...

  8. ACM-ICPC 2018北京网络赛-A题 Saving Tang Monk II-优先队列

    做法:优先队列模板题,按步数从小到大为优先级,PASS掉曾经以相同氧气瓶走过的地方就好了 题目1 : Saving Tang Monk II 时间限制:1000ms 单点时限:1000ms 内存限制: ...

  9. 2018北京网络赛D 80days (尺取)

    #1831 : 80 Days 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 80 Days is an interesting game based on Jules ...

随机推荐

  1. java求两个数中的大数

    java求两个数中的大数 java中的max函数在Math中 应用如下: int a=34: int b=45: int ans=Math.max(34,45); 那么ans的值就是45.

  2. 豆瓣图书Top250

    从豆瓣图书Top250抓取数据,并通过词云图展示 导入库 from lxml import etree #解析库 import time #时间 import random #随机函数 import ...

  3. kafka消息深入学习

    Kafka是一个分布式的基于发布/订阅模式的消息队列,主要应用于大数据实时处理领域. 1  快写  快读 看下面的图: 传统应用是  硬件到缓存,到应用 再socket进行传输,再进行网络传输,再到用 ...

  4. QT MSVC2017 ratio chrono

    如果引用了stdint.h可能会引发一些列错误,各种未申明和语法错误. 参加以下帖子解决问题 https://github.com/ftylitak/qzxing/issues/54 When com ...

  5. JFinal教程

    自学JFinal总结 前言:每次搭建ssm框架时,就像搬家一样,非常繁杂,并且还容易出错.正好了解到JFinal极简,无需配置即可使用,在这里记录下学习的过程. 感谢:非常感谢此网站发布的教程,非常详 ...

  6. $.extend() $.fn.extend()

    (非原创)jQuery为开发插件提拱了两个方法,分别是:jQuery.fn.extend();jQuery.extend();虽然 javascript 没有明确的类的概念,但是用类来理解它,会更方便 ...

  7. 17. final 关键字

    1.flnal修饰成员变量   1)定义: 如果一个变量不想被修改,那么就用final修饰 2)语法 public static final double PI=3.14; 3)注意 1. 被fina ...

  8. 酷狗mac版如何新建歌单?酷狗mac版收藏歌单方法

    很多朋友们都喜欢使用酷狗音乐听音乐,不过最近有使用酷狗mac音乐播放器的Mac新用户,想要新建歌单收藏歌单,但有不知道如何操作,那么苹果电脑酷狗mac版如何新建歌单收藏歌单呢?针对此问题,本文给大家介 ...

  9. Java之Java的文件结构(才不是叛教!)

    Java从入门到恰饭之文件结构,使用IDEA开发. 新建包 包名一般选择公司域名(https://tieba.baidu.com/)的反转 创建完成是这样的 对应的三层文件夹 我们创建一个类 pack ...

  10. C#反射从入门到放弃(这部分遇到的新东西太多了让人接受不能)

    首先,我们需要知道type,type是类型的类型(笑 官方点的说法是,BCL声明了一个Type抽象类,它被设计用来包含类型的特性, 使用这个类的对象(抽象类的对象?这显然是错误的,但是这里用的其实是T ...