P2521 防线修建

 上凸包最好用水平排序做,如果用极角序会很难做。

坑点:set erase一个元素之后,其他元素的指针不改变。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
typedef pair<lint,lint> pii;
const int maxn = 100001;
const double eps = 1e-12;
const double PI = acos(-1.0);
int sgn(double x)
{
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    else return 1;
}
struct Point
{
    double x,y;
    Point(){}
    Point(double _x,double _y)
    { x = _x;y = _y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x - b.x,y - b.y);
    }
//叉积
    double operator ^(const Point &b)const
    {
        return x*b.y - y*b.x; }
//点积
    double operator *(const Point &b)const
    {
        return x*b.x + y*b.y; }
//绕原点旋转角度B(弧度值),后x,y的变化
    bool operator <( const Point& b )const{
        if( x == b.x ) return y < b.y;
        return x < b.x;
    }
};
double dist(Point a,Point b)
{
    return sqrt((a-b)*(a-b));
}
int dist2(Point a,Point b)
{
    return (a-b)*(a-b);
}
const lint maxq = 200005;
pii Q[maxq];
lint vis[maxn];
Point p[maxn];
double ans[maxq],res;
set<Point> se;
void Insert( Point x ) {
    auto p = se.lower_bound(x);
    auto r = p,l = p;
    l--;
    if( ((x-*l)^(*r-*l)) >= 0 ) return;
    res -= dist(*l,*r);
    auto t = r;t++;
    while( t != se.end() ){
        if( ((*t-x)^( *t-*r )) <= 0 ) break;
        auto c = r;
        res -= dist( *r,*t );
        r++;t++;
        se.erase( c );
    }
    res += dist( x,*r );
    if( l != se.begin() ){
        t = l;t--;
        while( l != se.begin() ){
            if( ((*t-*l)^(*t-x))<= 0 ) break;
            res -= dist( *l,*t );
            auto c = l;
            l--;t--;
            se.erase(c);
        }
    }
    res += dist( *l,x );
    se.insert(x);
}
int main(){
    lint n,x,y;
    scanf("%d%d%d",&n,&x,&y);
    se.insert( Point(0,0) );se.insert(Point(x,y));se.insert(Point(n,0));
    res =  dist( Point(x,y),Point(n,0) ) + dist( Point(0,0),Point(x,y) );
    lint m,tot = 1,q;
    scanf("%d",&m);
    for( lint x,y,i = 1;i <= m;i++ ){
        scanf("%d%d",&x,&y);
        p[tot++] = Point(x,y);
    }
    scanf("%d",&q);
    for( lint f,x,i = 1;i <= q;i++ ){
        scanf("%d",&f);
        if( f == 1 ){
            scanf("%d",&x);
            Q[i] = pii( f,x );
            vis[x] = 1;
        }else{
            Q[i] = pii( f,0 );
        }
    }
    for( lint i = 1;i <= m;i++ ){
        if(vis[i]) continue;
        Insert(p[i]);
    }
    for( lint i = q;i >= 1;i-- ){
        if( Q[i].first == 1 ){
            Insert( Point( p[Q[i].second] ) );
        }else{
            ans[i] = res;
        }
    }
    for( lint i = 1;i <= q;i++ ){
        if( Q[i].first == 2 )
        printf("%.2lf\n",ans[i]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值