BZOJ 1137: [POI2009]Wsp 岛屿

Description

一个凸多边形,任意两点间有连边,有一些边不能使用,求\(1\)到\(n\)最短距离,\(n\leqslant 10^5,m\leqslant 10^6\)。

Solution

半平面交.

这个路是可以在交点拐上另一条路的..然后就成了几个半平面,按顺序加入可以直接用栈来维护了..

Code

/**************************************************************
    Problem: 1137
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:6604 ms
    Memory:74576 kb
****************************************************************/
 
#include <bits/stdc++.h>
using namespace std;
 
namespace CG {
    typedef double LD;
    const LD eps = 1e-8;
    #define sqr(x) ((x)*(x))
     
    int dcmp(LD x) { return fabs(x)<eps?0:(x>0?1:-1); }
    struct Point {
        LD x,y;
        Point(LD _x=0,LD _y=0) :x(_x),y(_y) { }
    };
    typedef Point Vector;
     
    Vector operator + (const Vector &a,const Vector &b) { return Vector(a.x+b.x,a.y+b.y); }
    Vector operator - (const Vector &a,const Vector &b) { return Vector(a.x-b.x,a.y-b.y); }
    Vector operator * (const Vector &a,const LD &b) { return Vector(a.x*b,a.y*b); }
     
    LD Cross(const Vector &a,const Vector &b) { return a.x*b.y-a.y*b.x; }
    LD get_a(const Vector &a) { return atan2(a.y,a.x); }
    LD dis(const Point &a,const Point &b) { return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); }
     
    struct Line {
        Point p;
        Vector v;
        LD ang;
        Line(Point _p=Point(),Vector _v=Vector()) :p(_p),v(_v) { ang=get_a(_v); }
        Point get_p(LD t) { return p+v*t; }
        int chkleft(Point pt) { return Cross(v,pt-p)>0; }
    };
    int cmpa(const Line &a,const Line &b) { return a.ang<b.ang; }
     
    Point get_l_l(Line a,Line b) {
        Vector u=a.p-b.p;
        LD t=Cross(b.v,u)/Cross(a.v,b.v);
        return a.get_p(t);
    }
}
 
using namespace CG;
 
typedef pair<int,int> pr;
 
const int N = 1e6+50;
int n,m;
Point p[N];
vector<int> pp[N];
vector<Line> ls;
vector<Point> pt;
 
int tp;
Line stk[N];
void insert(Line x) {
    while(tp>=2 && x.chkleft(get_l_l(stk[tp],stk[tp-1]))) tp--;
    stk[++tp]=x;
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        p[i]=Point(u,v);
    }
    for(int i=1;i<=m;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        if(u>v) swap(u,v);
        pp[u].push_back(v);
    }
    for(int i=1,j,k,t=0;i<=n;i++) {
        sort(pp[i].begin(),pp[i].end(),greater<int>());
        for(j=n,k=0;k<(int)pp[i].size() && j>t;k++,j--) if(pp[i][k]!=j) break;
        if(j>t) insert(Line(p[i],Point(p[t=j]-p[i])));
    }
    double ans=0;
    Point lt=p[1],tmp;
    for(int i=2;i<=tp;i++) tmp=get_l_l(stk[i-1],stk[i]),ans+=dis(lt,tmp),lt=tmp;
    ans+=dis(lt,p[n]);
    printf("%.8lf\n",ans);
    return 0;
}

  

posted @ 2017-04-17 09:13  北北北北屿  阅读(157)  评论(0编辑  收藏  举报