zoukankan      html  css  js  c++  java
  • 防线修建 BZOJ 2300

    防线修建

    【问题描述】

    近来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)和首都这三个城市是一定需要保护的。

    上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度

    如果,这个时候撤销B点的保护,那么防线变成下图 

    【输入格式】

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

    第二行,一个整数m。

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

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

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

    【输出格式】

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

    【样例输入】

    4 2 1

    2

    1 2

    3 2

    5

    2

    1 1

    2

    1 2

    2

    【样例输出】

    6.47

    5.84

    4.47

    【数据范围】

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

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

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


    题解:

    题意即为支持删点维护一个上凸壳

    由于只需要支持删点的操作

    那么离线倒序处理,就变为加点操作

    若要加入的点在凸包内,那就把它丢掉······

    如果这个点在凸包外

    分别考虑这个点左右两边的点

    向两个方向维护上凸壳

    这个过程用set实现

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<cstdio>
      6 #include<cmath>
      7 #include<set>
      8 using namespace std;
      9 inline int Get()
     10 {
     11     int x = 0;
     12     char c = getchar();
     13     while('0' > c || c > '9') c = getchar();
     14     while('0' <= c && c <= '9')
     15     {
     16         x = (x << 3) + (x << 1) + c - '0';
     17         c = getchar();
     18     }
     19     return x;
     20 }
     21 const int me = 200233;
     22 int n, m, x, y, e;
     23 int nu;
     24 double sum;
     25 struct dot
     26 {
     27     int x, y;
     28     inline bool operator < (const dot &z) const
     29     {
     30         if(x != z.x) return x < z.x;
     31         return y < z.y;
     32     }
     33 };
     34 dot o;
     35 dot a[me];
     36 int flag[me];
     37 bool vis[me];
     38 int num[me];
     39 double ans[me];
     40 multiset<dot> c;
     41 inline double Dis(const int &ax, const int &ay, const int &bx, const int &by)
     42 {
     43     return sqrt((ax - bx) * (ax - bx) + (ay - by) * (ay - by));
     44 }
     45 inline int Cross(const int &ax, const int &ay, const int &bx, const int &by)
     46 {
     47     return ax * by - bx * ay;
     48 }
     49 inline void Add(dot v)
     50 {
     51     multiset<dot>::iterator l = c.upper_bound(v), r = l;
     52     --l;
     53     if(Cross((r -> x) - (l -> x), (r -> y) - (l -> y), v.x - (l -> x), v.y - (l -> y)) <= 0) return;
     54     sum -= Dis((l -> x), (l -> y), (r -> x), (r -> y));
     55     multiset<dot>::iterator now;
     56     while(l != c.begin())
     57     {
     58         now = l;
     59         --l;
     60         if(Cross(v.x - (l -> x), v.y - (l -> y), (now -> x) - (l -> x), (now -> y) - (l -> y)) >= 0)
     61         {
     62             ++l;
     63             break;
     64         }
     65         sum -= Dis((now -> x), (now -> y), (l -> x), (l -> y));
     66         c.erase(now);
     67     }
     68     while(true)
     69     {
     70         now = r;
     71         ++r;
     72         if(r == c.end())
     73         {
     74             --r;
     75             break;
     76         }
     77         if(Cross(v.x - (r -> x), v.y - (r -> y), (now -> x) - (r -> x), (now -> y) - (r -> y)) <= 0)
     78         {
     79             --r;
     80             break;
     81         }
     82         sum -= Dis((now -> x), (now -> y), (r -> x), (r -> y));
     83         c.erase(now);
     84     }
     85     c.insert(v);
     86     sum += Dis((l -> x), (l -> y), v.x, v.y) + Dis(v.x, v.y, (r -> x), (r -> y));
     87 }
     88 int main()
     89 {
     90     o.x = o.y = 0; 
     91     c.insert(o);
     92     o.x = n = Get();
     93     c.insert(o);
     94     o.x = x = Get();
     95     o.y = y = Get();
     96     c.insert(o);
     97     m = Get();
     98     sum = Dis(0, 0, x, y) + Dis(x, y, n, 0);
     99     for(int i = 1; i <= m; ++i)
    100     {
    101         a[i].x = Get();
    102         a[i].y = Get();
    103     }
    104     e = Get();
    105     for(int i = 1; i <= e; ++i)
    106     {
    107         flag[i] = Get();
    108         if(flag[i] == 1)
    109         {
    110             num[i] = Get();
    111             vis[num[i]] = true;
    112         }
    113     }
    114     for(int i = 1; i <= m; ++i)
    115         if(!vis[i])
    116             Add(a[i]);
    117     for(int i = e; i >= 1; --i)
    118     {
    119         if(flag[i] == 1) Add(a[num[i]]);
    120         else ans[++nu] = sum;
    121     }
    122     for(int i = nu; i >= 1; --i)
    123         printf("%.2lf
    ", ans[i]);
    124 }
  • 相关阅读:
    拥抱webpack4,有效缩减构建时间57%+
    可能是最详细的UMD模块入门指南
    Chrome远程调试手机端UC浏览器
    sea.js的同步魔法
    在Linux和Windows系统中输出目录结构
    从部署上做到前后端分离
    一种在地图中处理曲线的通用方法
    vue项目中引入iconfont
    前端路上的自我怀疑----------自我突破
    表格布局----基于bootstrap样式 布局
  • 原文地址:https://www.cnblogs.com/lytccc/p/6241014.html
Copyright © 2011-2022 走看看