BZOJ 1137: [POI2009]Wsp 岛屿(半平面交求周长)

124 篇文章 0 订阅
86 篇文章 0 订阅

题目
因为可以在相交线段上换乘。所以容易想到答案就是包含1-n这条边的内部不包含边的凸包的周长。
发现对于每个点,只有标号最大的邻接点有用。
然后半平面交即可。
再也不敢用map了, 1 0 6 10^6 106直接卡到TLE,换了vector+sort直接B站第一页

AC Code:

#include<bits/stdc++.h>
#define maxn 100005
#define eps 1e-6
using namespace std;

int n,m;
vector<int>G[maxn];

double sqr(double a){ return a*a; }
struct Point{
    double x,y;
    inline Point(double x=0,double y=0):x(x),y(y){}
    inline Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
    inline Point operator +(const Point &B)const{ return Point(x+B.x,y+B.y); }
    inline double operator *(const Point &B)const{ return x*B.y-y*B.x; }
    inline Point operator *(const double &B)const{ return Point(x*B,y*B); }
    inline double dist(const Point &B)const{ return sqrt(sqr(x-B.x)+sqr(y-B.y)); }
}P[maxn];

struct Line{
    Point A,B;
    double ag;
}L[maxn*2];int tot;
int id[maxn*2];
inline int sgn(double a){ return a<-eps?-1:a>eps?1:0; }
inline bool inLeft(const Point &P,const Point &A,const Point &B){
    return (B-A) * (P-A) > 0;
}
inline bool cmp(const int &u,const int &v){
    if(sgn(L[u].ag-L[v].ag)) return L[u].ag < L[v].ag;
    return inLeft(L[u].A,L[v].A,L[v].B);
}
inline Point Ipt(const Point &p1,const Point &p2,const Point &p3,const Point &p4){
    Point u = p2 - p1 , v = p4 - p3 , w = p2 - p4;
    return p2 + (p1 - p2) * ((w * v) / (u * v));
}
int qL[maxn*2],l,r;
Point qp[maxn*2];

char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>void read(T &res){
	char ch;bool f = 0;
	for(;!isdigit(ch=getc());) if(ch=='-') f=1;
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
	(f) && (res = -res);
}

int main(){
    read(n),read(m);
    for(int i=1;i<=n;i++) read(P[i].x),read(P[i].y);
    for(int i=1;i<=m;i++){
        int x,y;
        read(x),read(y);
        if(x > y) swap(x,y);
		G[x].push_back(y);
    }
    for(int i=1;i<=n;i++){
        int j;
		sort(G[i].begin(),G[i].end());
		int k = G[i].size() - 1;
        for(j=n;k>=0&&j>=i&&G[i][k]==j;j--,k--);
        if(j>i){
            L[++tot].A = P[j] , L[tot].B = P[i];
            L[tot].ag = atan2(P[i].y-P[j].y,P[i].x-P[j].x);
            id[tot] = tot;
        } 
    }
    L[++tot].A=P[1],L[tot].B=P[n];
    L[tot].ag = atan2(P[n].y-P[1].y,P[n].x-P[1].x);
    id[tot] = tot;
    sort(id+1,id+1+tot,cmp);
    
    qL[r++] = id[1];
    for(int i=2,u;i<=tot;i++)
        if(sgn(L[u=id[i]].ag - L[id[i-1]].ag)){
            for(;r-l>=2 && !inLeft(qp[r-2],L[u].A,L[u].B);r--);
            for(;r-l>=2 && !inLeft(qp[l],L[u].A,L[u].B);l++);
            qL[r++] = u;
            if(r-l>=2) 
                qp[r-2] = Ipt(L[qL[r-2]].A,L[qL[r-2]].B,L[u].A,L[u].B);
        }
    //for(;r-l>=2 && !inLeft(qp[l],L[qL[r-1]].A,L[qL[r-1]].B);l++);
    for(;r-l>=2 && !inLeft(qp[r-2],L[qL[l]].A,L[qL[l]].B);r--);
    if(r-l <= 2) printf("%.10lf\n",P[1].dist(P[n]));
    else
    {
        qp[r-1] = Ipt(L[qL[l]].A,L[qL[l]].B,L[qL[r-1]].A,L[qL[r-1]].B);
        double ans = 0;
        qp[r] = qp[l];
        for(int i=l;i<=r-1;i++)
            ans += qp[i+1].dist(qp[i]);
        printf("%.10lf\n",ans-P[1].dist(P[n]));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值