HihoCoder 1834 The Mole ICPC2018 北京网络赛 点到线段最短距离 分块

#include <bits/stdc++.h> //卡精度卡的蛋疼妈蛋
using namespace std;
#define LL long long
const int maxn=1e4+10;
const int blk=256;
vector<int>mp[blk*blk];
#define eps 1e-8
#define inside(x,y) (x>=0&&x<blk&&y>=0&&y<blk)
int vis[maxn];
struct point
{
    double x,y;
    point(double x=0,double y=0):x(x),y(y){}
    void in(){scanf("%lf%lf",&x,&y);}
    double operator ^(const point &a)const{
        return x*a.y-y*a.x;
    }
    double operator *(const point &a)const{
        return x*a.x+y*a.y;
    }
    bool operator ==(const point &a)const{
        return x==a.x&&y==a.y;
    }
    point operator +(const point &a)const {
        return point(x+a.x,y+a.y);
    }
    point operator -(const point &a) const {
        return point(x-a.x,y-a.y);
    }
    double len() {
        return hypot(x,y);
    }
    void getidx(int &a,int &b) { 
        a=x/blk;b=y/blk;
    }
    double dis(point &p) {
        return hypot(x-p.x,y-p.y);
    }
};
struct line
{
    point s,e;
    void init(){s.in();e.in();}
    void getidx(int id){
        int a,b,aa=-1,bb=-1;
        point t=e-s;
        for(int i=0;i<=blk;i++) //把整个平面分成256*256个块 对于每个点查询它最近的9个小块 
        {
            point p=s+point(t.x*i/blk,t.y*i/blk);
            p.getidx(a,b);
            if(a==aa&&b==bb)continue;
            mp[a*blk+b].push_back(id);
            aa=a;bb=b;
        }
    }
    double dis(point &p){
        if(s==e)return s.dis(p); //一直脑瓜想着是点到直线距离 蛋疼 这里线段为点
        if((p-s)*(e-s)<-eps) return s.dis(p); //以s为顶点的钝角
        if((p-e)*(s-e)<-eps) return e.dis(p); //以e为顶点的钝角
        return fabs(((s-p)^(e-p))/(e-s).len()); //面积除以底 
    }//点到线段距离分为上面4种情况
};
line l[maxn];

int main()
{
    #ifdef shuaishuai
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif // shuaishuai
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        l[i].init();
        l[i].getidx(i);
    }
    point p;
    for(int f=m;f>=1;f--)
    {
        p.in();
        int a,b,id=-1;
        p.getidx(a,b);
        double ans=1e18;
        for(int i=-1;i<2;i++)
            for(int j=-1;j<2;j++)
        {
            int x=a+i,y=b+j;
            if(!inside(x,y))continue;
            for(auto c:mp[x*blk+y]){
                if(vis[c]==f)continue;vis[c]=f; //这个标记很重要
                double dis=l[c].dis(p);
                if(dis+eps<ans) ans=dis,id=c;
                else if(fabs(dis-ans)<eps) id=min(id,c);
            }
        }
        if(ans==1e18){
            for(int i=1;i<=n;i++)
            {
                double dis=l[i].dis(p);
                 if(dis+eps<ans) ans=dis,id=i;
                else if(fabs(dis-ans)<eps) id=min(id,i);
            }
        }
        printf("%d\n",id);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/polya/p/9808049.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值