近来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,表示修建防线的花费,保留两位小数
4 2 1
2
1 2
3 2
5
2
1 1
2
1 2
2
6.47
5.84
4.47
m<=100000,q<=200000,n>1
所有点的坐标范围均在10000以内, 数据保证没有重点
计算几何题,观察题面发现删点非常不好做,因为是整个凸包往下坍缩,要维护一大堆奇怪的东西。但是发现对于一个凸包,加入一个点的操作是非常好做的,所以我们就把询问离线,然后倒着做。用 set \text{set} set 维护一下加入这个点之后的左边和右边的点,判断是否满足凸包性质,不断删点就可以了。代码写起来也很短,不像其他的计算几何题。
//Dlove's template
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define R register
#define ll long long
#define ull unsigned long long
#define db double
#define ld long double
#define sqr(_x) ((_x) * (_x))
#define Cmax(_a, _b) ((_a) < (_b) ? (_a) = (_b), 1 : 0)
#define Cmin(_a, _b) ((_a) > (_b) ? (_a) = (_b), 1 : 0)
#define Max(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define Min(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define Abs(_x) (_x < 0 ? (-(_x)) : (_x))
using namespace std;
namespace Dntcry
{
inline int read()
{
R int a = 0, b = 1; R char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) (c == '-') ? b = -1 : 0;
for(; c >= '0' && c <= '9'; c = getchar()) a = (a << 1) + (a << 3) + c - '0';
return a * b;
}
inline ll lread()
{
R ll a = 0, b = 1; R char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) (c == '-') ? b = -1 : 0;
for(; c >= '0' && c <= '9'; c = getchar()) a = (a << 1) + (a << 3) + c - '0';
return a * b;
}
const int Maxm = 100010, Maxq = 200010;
int n, m, q;
db Ans[Maxq], now;
bool vis[Maxm];
struct Point
{
int x, y;
bool operator < (const Point &b) const
{
return x == b.x ? y < b.y : x < b.x;
}
Point operator - (const Point &b) const
{
return (Point){x - b.x, y - b.y};
}
int operator * (const Point &b) const
{
return x * b.y - y * b.x;
}
}cap, P[Maxm], del[Maxq];
db dis(R Point a, R Point b)
{
return sqrt(0.0 + sqr(a.x - b.x) + sqr(a.y - b.y));
}
set<Point>S;
set<Point>::iterator l, r, t;
int tot1, tot2, qus[Maxq];
void Insert(R Point x)
{
r = S.lower_bound(x), l = r;
l--;
if((*r - *l) * (x - *l) < 0) return ;
now -= dis(*l, *r);
S.insert(x);
while(1)
{
t = r++;
if(r == S.end()) break;
if((*r - x) * (*t - x) > 0) break;
now -= dis(*r, *t);
S.erase(t);
}
while(l != S.begin())
{
t = l--;
if((*t - x) * (*l - x) > 0) break;
now -= dis(*l, *t);
S.erase(t);
}
S.insert(x);
l = r = S.find(x);
l--, r++;
now += dis(*l, x) + dis(x, *r);
}
int Main()
{
n = read();
S.insert((Point){0, 0});
S.insert((Point){n, 0});
cap = (Point){read(), read()};
S.insert(cap);
now = dis(cap, (Point){0, 0}) + dis(cap, (Point){n, 0});
m = read();
for(R int i = 1; i <= m; i++) P[i] = (Point){read(), read()};
q = read();
for(R int i = 1, x; i <= q; i++)
{
R int opt = read();
if(opt & 1) x = read(), del[++tot1] = P[x], vis[x] = 1;
else qus[++tot2] = tot1;
}
for(R int i = 1; i <= m; i++) if(!vis[i]) Insert(P[i]);
for(R int i = tot2, w = tot1; i; i--)
{
while(w > qus[i]) Insert(del[w]), w--;
Ans[i] = now;
}
for(R int i = 1; i <= tot2; i++) printf("%.2lf\n", Ans[i]);
return 0;
}
}
int main()
{
return Dntcry :: Main();
}