[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\n",ans[i]);



}

 

posted on 2018-08-27 15:20  怡红公子  阅读(153)  评论(0编辑  收藏  举报