• [HAOI2011]防线修建


    题目描述

    近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务:

    1. 给出你所有的A国城市坐标

    2. A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了

    3. A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少

    你需要对每次询问作出回答。注意单位1长度的防线花费为1。

    A国的地形是这样的,形如下图,x轴是一条河流,相当于一条天然防线,不需要你再修建

    A国总是有两个城市在河边,一个点是(0,0),一个点是(n,0),其余所有点的横坐标均大于0小于n,纵坐标均大于0。A国有一个不在(0,0)和(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。

    输入输出格式

    输入格式:

    第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。

    第二行,一个整数m。

    接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。

    再接下来一个整数q,表示修改和询问总数。

    接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。

    输出格式:

    对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数

    输入输出样例

    输入样例#1: 复制
    4 2 1                                
    2                                 
    1 2                               
    3 2                               
    5                                 
    2
    1 1
    2
    1 2
    2
    输出样例#1: 复制
    6.47
    5.84
    4.47

    说明

    数据范围:

    30%的数据m<=1000,q<=1000

    100%的数据m<=100000,q<=200000,n>1

    所有点的坐标范围均在10000以内, 数据保证没有重点

    离线后问题变成维护动态凸壳,只有插入点的操作,根据x坐标维护平衡二叉树,

    插入点x,找到x点的左右两点,判断x是否在凸壳外,然后维护x两边的凸壳

    因为set是红黑树实现,把凸包的点放进set.

    iterator x=s.begin();

    x--;

    x++;

    此时x不一定等于s.begin()

    #include<iostream>
    #include<set>
    #include<math.h>
    #include<stdio.h>
    #include<stdlib.h>
    using namespace std;
    
    typedef struct{
        double x,y;
        bool shouldInsert;
    }Point;
    Point p[100005];
    set<Point> s;
    double now=0;
    
    bool operator<(const Point& a,const Point&b){
        return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
    Point operator-(const Point&a,const Point&b){
        Point c;
        c.x=a.x-b.x;
        c.y=a.y-b.y;
        return c;
    }
    
    double dist(const Point&a,const Point&b){
        Point c=a-b;
        return sqrt(c.x*c.x+c.y*c.y);
    }
    double cross(const Point&a,const Point&b){
        return a.x*b.y-a.y*b.x;
    }
    
    void insert(int d){
        set<Point>::iterator left=s.upper_bound(p[d]),right=left--,tmpr,tmpl;
        if(cross(*left-p[d],*right-p[d])<=0) return;
        now-=dist(*left,*right);
        while(true)
        {
            tmpr=right;right++;
            if(right==s.end()) break;
            if(cross(p[d]-*right,*tmpr-*right)>=0)
            {
                now-=dist(*tmpr,*right);
                s.erase(tmpr);
            }
            else break;
        }
        
        while(true)
        {
            tmpl=left;left--;
            if(tmpl==s.begin()) break;
            if(cross(p[d]-*left,*tmpl-*left)<=0)
            {
                now-=dist(*tmpl,*left);
                s.erase(tmpl);
            }
            else break;
        }
    
        s.insert(p[d]);
        now+=dist(p[d],*tmpl)+dist(p[d],*tmpr);
    }
    
    
    double ans[200005];
    int main()
    {
        int n;
        double x,y;
        scanf("%d",&n);
        scanf("%lf %lf",&x,&y);
        Point a,b,c;
        a.x=0;a.y=0;b.x=n;b.y=0;c.x=x;c.y=y;
        s.insert(a);s.insert(b);s.insert(c);
        now+=dist(a,c)+dist(b,c);
        
        int m;
        scanf("%d",&m);
        for(int i=1;i<=m;++i)
        {
            scanf("%lf %lf",&x,&y);
            p[i].x=x;p[i].y=y;p[i].shouldInsert=true;
        }
        
        int q;
        int delCount=0;int delCity[200005];
        int queryCount=0;int queryCity[200005];
        scanf("%d",&q);
        for(int i=1;i<=q;++i)
        {
            int cmd,city;
            scanf("%d",&cmd);
            if(cmd==1) 
            {
                scanf("%d",&city);
                delCount++;
                delCity[delCount]=city;
                p[city].shouldInsert=false;
            }
            if(cmd==2) {queryCount++;queryCity[queryCount]=delCount;}
        }
        
        for(int i=1;i<=m;++i)
        if(p[i].shouldInsert==true)
        insert(i);
        
        for(int i=queryCount;i>=1;--i)
        {
            while(delCount>queryCity[i])
            {
                insert(delCity[delCount]);
                delCount--;
            }
            ans[i]=now;
        }
        
        for(int i=1;i<=queryCount;++i)
        printf("%.2f
    ",ans[i]);
    
    
    
    }
  • 相关阅读:
    RapidJSON简介及使用(转)
    唯一ID生成算法剖析(转)
    OpenCV相机标定及距离估计(单目)(转)
    Linux 格式化分区 报错Could not stat --- No such file or directory 和 partprobe 命令
    Linux下chkconfig命令详解
    Linux设置开机服务自动启动
    CentOS 6.3下Samba服务器的安装与配置
    vmware 命令行启动虚拟机
    Linux自动修改IP脚本(手动编写)
    网络高清视频监控传输:如何减少带宽消耗?
  • 原文地址:https://www.cnblogs.com/noip/p/9542412.html
Copyright © 2020-2023  润新知