[BZOJ2300][HAOI2011]防線修建

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

計算幾何題,觀察題面發現刪點非常不好做,因爲是整個凸包往下坍縮,要維護一大堆奇怪的東西。但是發現對於一個凸包,加入一個點的操作是非常好做的,所以我們就把詢問離線,然後倒着做。用 set\text{set} 維護一下加入這個點之後的左邊和右邊的點,判斷是否滿足凸包性質,不斷刪點就可以了。代碼寫起來也很短,不像其他的計算幾何題。

//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();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章