Description
近來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)和首都這三個城市是一定需要保護的。
Input
第一行,三個整數n,x,y分別表示河邊城市和首都是(0,0),(n,0),(x,y)。
第二行,一個整數m。
接下來m行,每行兩個整數a,b表示A國的一個非首都非河邊城市的座標爲(a,b)。
再接下來一個整數q,表示修改和詢問總數。
接下來q行每行要麼形如1 i,要麼形如2,分別表示撤銷第i個城市的保護和詢問。
Output
對於每個詢問輸出1行,一個實數v,表示修建防線的花費,保留兩位小數
Sample Input
4 2 1
2
1 2
3 2
5
2
1 1
2
1 2
2
Sample Output
6.47
5.84
4.47
HINT
m<=100000,q<=200000,n>1
所有點的座標範圍均在10000以內, 數據保證沒有重點
Solution
計算幾何題,觀察題面發現刪點非常不好做,因爲是整個凸包往下坍縮,要維護一大堆奇怪的東西。但是發現對於一個凸包,加入一個點的操作是非常好做的,所以我們就把詢問離線,然後倒着做。用 維護一下加入這個點之後的左邊和右邊的點,判斷是否滿足凸包性質,不斷刪點就可以了。代碼寫起來也很短,不像其他的計算幾何題。
//Dlove's template
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#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();
}