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

你可能感兴趣的:(计算几何)